RSS feed

Nutsmuggling

viewWillAppear: not being called inside a UINavigationController

I just stumbled on a small problem that gave me a great headache. I changed the view hierarchy to implement flipping preferences on the back of my App’s main view. Accordingly, I had to move some stuff out of the nibs and into the code. Iin other words, some heavy refactoring, and without testing (I know, bad bad me).

So basically I now have a root UIViewController which has a UINavigationController as a subview; this, in turn, loads a number of UIViewControllers to navigate my items hierarchy.

Today, while working on cosmestic/usability improvements, I realised that something was definitely not working. When moving back and forth in my items, data were not refreshed. This pointed to one culprit, viewWillAppear not being called in the UIViewControllers.

After some googling I found out that if you add a UINavigationController as a subview of a UIViewController subclass, you must explicitly call its viewWillAppear method from its container; otherwise, they won’t be called, and when moving back and forth in the navigation tree, your UIViewControllers’ viewWillAppear: methods won’t be called.

It’s quite simple; assuming that projectNavigationController is a navigation controller added as a a subview of this UIViewController subclass, just make sure you add this simple call:

-(void)viewWillAppear:(BOOL)animated { 
	[super viewWillAppear:animated];
	[projectNavigationController viewWillAppear:animated];
}

Of course the same applies to your other viewWill/Did methods

-(void)viewWillDisappear:(BOOL)animated { 
	[super viewWillDisappear:animated];
	[projectNavigationController viewWillDisappear:animated];
}
-(void)viewDidAppear:(BOOL)animated { 
	[super viewDidAppear:animated];
	[projectNavigationController viewDidAppear:animated];
}
-(void)viewDidDisappear:(BOOL)animated { 
	[super viewDidDisappear:animated];
	[projectNavigationController viewDidDisappear:animated];
}

It’s quite simple, but wasn’t obvious for me at first.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Google
  • Technorati
  • StumbleUpon
  • Furl
  • Reddit

18 responses to “viewWillAppear: not being called inside a UINavigationController”

  1. Lovedeity says:

    I have the exact same problem. Mine is a little more insidious.

    UIViewController <- top level, its view is the only window subview

    UITabBarController <- its view is the only subview of the top level UIViewController view

    UINavigationController <- inside one of the tabs

    No matter what I’ve tried, I cannot get the UINavigationController to send its messages. Most likely because the UITabBarController doesn’t send its messages either. Evil evil evil.

    …any chance you found a way around that one?

  2. Davide says:

    Lovedeity, I didn’t have the chance to try something like your hierarchy, but Iwould say that you need to have the root controller forward the calls to the tab bar controller, and the tab controller forward the call to the navigation controller.
    So you should include the code I’ve shown both in the root controller and in the tab bar controller. Have you tried something like this? Davide

  3. Lovedeity says:

    I’m pretty sure I tried that, yeah.

    My alternative solution is to just start out with the UITabBarController as the subview of the main window. Then whenever I need to show the flipside, I remove that view from the window, add that view as the subview of my flipper controller, add the flipper view to the window, then perform the flip. Not as elegant as I’d like, though.

  4. Davide says:

    Well, if it does the job :)
    Very strange though, just the fact of having to pass these will/did appear calls exlicitly seems weird to me, but I am not a seasoned enough cocoa programmer, I can’t give an informed judgement. If anyone has a comment on my or lovedeity’s issue, please leave a comment .

  5. Rodrigo says:

    Hi,

    I had exactly the same problem. UITabBarController does not dispatch the calls to the view controllers it contains. I am testing this on iPhone OS 3 beta 2.

    I fixed it by creating a private category of UITabBarController. Create a new category of UITabBarController and implement the viewWillAppear, viewWillDisappear, etc:

    @implementation UITabBarController (Private)

    • (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; for (UIViewController *viewCtrl in self.viewControllers) { [viewCtrl viewWillAppear:animated]; } }

    @end

  6. Things that were not immediately obvious to me » Blog Archive » viewWillAppear says:

    [...] here [...]

  7. Henry Müller says:

    Many thanks! I surfed through many forum and blog posts befor i found your solution. Sometimes such basic things are hard to find…

  8. Matt Thomas says:

    Thanks! This was driving me nuts but it fixed the issue!!!

  9. Justin Anderson says:

    You can also set your root UIViewController as the UINavigationController’s delegate and implement UINavigationController’s delegate method -navigationController:willShowViewController:animated: in your UIViewController. e.g.

    • (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [viewController viewWillAppear:animated]; }
  10. Colonel Nikolai says:

    I’ve had a similar problem but it’s kind of the inverse.

    I have a Navigation-based application setup with the AppDelegate pushing a Navigation Controller that has a UITableView as a sub-view of that. This then pushes more views to the nav controller. Now my problem is that the SUB views are getting the orientation change events no problem, but the root Table View controller NEVER gets them.

    Your advice probably translates to my set up, but I can’t figure out how. What am I not getting?

  11. Dustin Clark says:

    Word to the wise…do not use a root view controller and add views to it like so:

    [rootViewController.view addSubview:secondViewController.view];

    Where second view controller is a view controller, navigation controller, or a tab bar controller. Bottom line, the only place you should use addSubview on on a view controllers view should be [window addSubview:viewController.view]; You’ll be writing hacks and workarounds throughout your app to keep it working…and those aren’t guaranteed to work in the next OS release…

    If you must use a root view controller because you dynamically determine your main application view controller (like I do), use [rootViewController presentModalViewController:secondViewController animated:NO]; Since you’re not animating it, it will appear when the app loads and you’ll never see the root view controller’s view. If you want to flip the second view controller in (like the original post), just present another modal on top with the desired animation….or, wrap presentModal..animated:NO with UIView animations.

  12. Samiq says:

    This one was really tricky, thanks for the heads up. This seems like a big bug from apple… but oh well that’s what this trials and errors are for.

    thanks!

  13. Corprew Reed says:

    If you set the UINavigationControllerDelegate to some random object (like the navigation view controller) and then add this method:

    • (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([viewController respondsToSelector:@selector(viewDidAppear:)]) { [viewController viewDidAppear:animated]; } }

    It will do what you expect.

  14. Brinley Ang says:

    Thanks, this saved me a load of headaches.

    Anyway, your comments template has a formatting error while appending nofollow rel tag to urls in comments.

  15. Poxi says:

    Thanks a lot. it did work well. you rescue me

  16. MooCow says:

    I stumbled upon this today and was grateful for your post outlining the fix. It’s a bit naff that it doesn’t just work – the framework shouldn’t need plumbing like this.

  17. Ben says:

    Thank you for the clear and succinct explanation. Wish I’d found this post earlier!

  18. Glasswing says:

    You rock! You saved me days of fighting with this issue. Thanks so much for the information. Fixed my problem immediately!

Leave a Reply