Iphone – How to properly release and switch views in multiview controller

cocoa-touchiphone

I'm trying to create a multiview controller for a game, in which one root view controller releases views before switching to another view. The sub view controllers are, in turn, sub-root view controllers themselves since they contain other view controllers.

For instance, my singlePlayerViewController will have a shakeObjectViewController and possibly others. Using actionsheets to switch between the views, with the app delegate as the actionsheet's delegate, everything works as expected when going from singlePlayer view to another.

But when I attempt to create a new singlePlayerViewController using the same init methods, the debugger throws me a EXC_BAD_ACCESS error when I try to insert a subview, namely shakeObjectViewController.view.

Initialization looks like this at the moment:
The app delegate initializes the window with the default init method,

- (void)applicationDidFinishLaunching:(UIApplication *)application {   
    // Override point for customization after application launch
   [window addSubview:rootViewController.view];
    [window makeKeyAndVisible];
}

Then in the rootViewController.m's viewDidLoad,

   if(singlePlayerViewController == nil) {

      SinglePlayerViewController *singleController = [[SinglePlayerViewController alloc]
                                       initWithNibName:@"SinglePlayerView" bundle:nil];
      self.singlePlayerViewController = singleController;
      [singleController release];
   }

   [self.view insertSubview:singlePlayerViewController.view atIndex:0];

Followed by singlePlayerViewController.m,

- (void)viewDidLoad {
   self.view.tag = kSinglePlayerView; // tag the view

   ShakeObjectViewController *shakeController = [[ShakeObjectViewController alloc]
                                       initWithNibName:@"ShakeObjectView" bundle:nil];
   self.shakeObjectViewController = shakeController;
   self.view = shakeController.view;
   [shakeController release];
}

Note how my singlePlayerViewController is not inserting subviews, but is instead replacing its own view with a sub-view controller's view. (Don't know if this is a good practice or not ❓ )

When switching views, the app delegate performs the following:

for(UIView *subview in [rootViewController.view subviews])
{   
   [subview removeFromSuperview];
}
[rootViewController.singlePlayerViewController release]

[rootViewController initMultiplayerView];

Then when switching back to single player mode, the same init method in rootViewController.m's viewDidLoad is executed, and the debugger throws the error on the "[self.view insertSubview:singlePlayerViewController.view atIndex:0];" line.

Any ideas as to why a new view isn't being created? I've tried setting the singlePlayerViewController to nil instead of releasing, but then the error is thrown on the "self.view = shakeController.view;" line.
It was my understanding that if the view property is currently nil, a new one is created automatically for you upon the next access to the view.

Is initWithNibName only meant to be executed once? Or is my design way too convoluted in terms of # view controllers?

Best Answer

Note how my singlePlayerViewController is not inserting subviews, but is instead replacing its own view with a sub-view controller's view. (Don't know if this is a good practice or not :?: )

Huge warning flag here. It sounds like you have one view with two view controllers. This is bad.

Consider inserting and removing subviews instead:

  • RootView
    • SinglePlayerView (can be removed and replaced with MutliplayerView)
      • ShakeView

This way you have 3 view with 3 view controllers.

It's the way the framework was meant to be used.

Related Topic