Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Juggling multiple UINavigationControllers using the App Delegate and ensuring UINavigationController correctly deallocs

I have a app which uses two UINavigationControllers - one for the menu system and one for the actual game. A common UINavigationController is declared in my appDelegate. When the app loads, it either loads the Menu or the Game's UINavigationController. And of course the player can then navigate between the two.

When going from the menu to the game, I create a new UINavigationController and present it as follows:

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

However, I've noticed that when I do this, the Menu's viewController never calls dealloc. Presumably because there's still a reference to something keeping it alive. I've found that when I explicitly set the App Delegate's UINavigationController to the new navigation controller, (before releasing the new navController) it releases the Menu. I do this as follows:

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
 appDelegate.navController = newNavController;
 [newNavController release];

Is this good practice? I've found that when navigating from the game back to the menu however, the same trick doesn't seem to work. I.e.

MainMenuViewController *menuViewController = [[MainMenuViewController alloc] init]; 
 UINavigationController *newNavController = [[UINavigationController alloc] initWithRootViewController:menuViewController];
 [menuViewController release];
 newNavController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
 [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. 
 MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
 appDelegate.navController = newNavController;
 [newNavController release];

never call's dealloc on the game's main ViewController. And when I navigate back to the game again, the menu's main ViewController is no longer released either.

Am I missing something when juggling UINavigationControllers?

Thank you,

Michael

EDIT: I've since realised that the reason my game's main ViewController was not deallocing, was because I has some NSTimers that I hadn't invalidated! However, I'm still curious to know if my above approach is correct, and that explicitly redefining the navController in the App Delegate is the correct way to allow the different UINavigationControllers to dealloc :)

like image 612
Smikey Avatar asked Nov 20 '10 14:11

Smikey


1 Answers

Make your life easier. Use a single UINavigationController, and maintain two separate View Controller stacks, which are just arrays of UIViewControllers. You can use [UINavigationController setViewControllers:animated:] to just swap the stacks out and leave the nav controller in place. Use UINavigationController.viewControllers to get the current stack to hold onto before replacing it. It's something like 14.3 billion times easier and cleaner than dealing with all the vagaries of multiple nav controllers.

like image 50
MahatmaManic Avatar answered Nov 11 '22 10:11

MahatmaManic