Search code examples
iphoneobjective-cxcodeuinavigationcontrolleruiapplicationdelegate

How to swap between 2 root view controllers


I have a game with two rootViewControllers - one for the Menu and the other for the Game itself.

When the user switches between the Game and the Menu, I want to switch the rootViewController. Ultimately my questions is, what is the best way to do this? Or is there another approach for switching stacks that makes more sense than having 2 rootViewControllers?

As it stands, I have an instance of a navigationController in my appDelegate. When I want to switch rootViewController, I initialise a new navigationController, set it's rootVC, then set this to the instance of the navController in the appDelegate. The code to transition from the menu to the game looks like this:

//Initialise the new Root Controller
GameViewController *rootController = [[GameViewController alloc] init];

UINavigationController *newNavController = [[UINavigationController alloc] initWithRootViewController:rootController];
[rootController release];   
newNavController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:newNavController animated:YES];

//Setting the appDelegate's navController to the new navController allows the menu to dealloc. 
//This must happen AFTER the newNavController has been loaded. 
MiniAppDelegate *appDelegate = (MiniAppDelegate *)[[UIApplication sharedApplication] delegate]; 
appDelegate.navController = newNavController;
[newNavController release];

Is this bad practice?? I have an issue with my app when it resumes from background and I think this might be what's causing it.


Solution

  • You might be going well by not presenting a modal view controller, but to use a UIViewController that manages the underlying view controllers.

    Similar to this:

    // MainNavigationController extends UINavigationController
    
    @property (nonatomic,retain) UIViewController childViewController
    
    -(void)viewDidLoad {
        self.childViewController = [MenuViewController alloc] initWithNibName...];
        [self pushViewController:childView...];
    }
    
    -(void)launchGame {
        self.childViewController = [GameViewController alloc] ... ];
        self.viewControllers = [NSArray array];
        [self pushViewController:childView...];
    }
    

    This way you hold a reference to your current view controller all the time and manage the displaying of them in one place.

    You should also pass both child view controllers a reference to the MainNavigationController so that you can use delegate methods.

    edit:

    To clarify things a bit regarding the first comment: Yes, the MainNavigationController is the starting point of your app which handles the displaying of the menu and the game itself.

    The line self.viewControllers = [NSArray array] is used to just empty out the list of current view controllers when launching a game. This is done to replace the menu with the game instead of just pushing it. This way, you don't have 8 view controllers when the user goes to the menu, to the game, to the menu and so on.

    A similar method would be used to open the menu while playing the game: A button would ask the MainViewController to open the menu. You can either to it the same way the launchGame method works or you can then present it the modal way to keep the game state or you put a smaller in-game menu before that or whatsoever - many ways to handle things from there on.