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.







January 4th, 2009 at 2:13 am
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?
January 4th, 2009 at 11:47 am
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
January 4th, 2009 at 8:45 pm
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.
January 4th, 2009 at 9:05 pm
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 .
April 12th, 2009 at 10:53 pm
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)
@end
June 10th, 2009 at 8:17 am
[...] here [...]
June 19th, 2009 at 5:56 pm
Many thanks! I surfed through many forum and blog posts befor i found your solution. Sometimes such basic things are hard to find…
July 23rd, 2009 at 9:42 pm
Thanks! This was driving me nuts but it fixed the issue!!!
August 20th, 2009 at 10:12 pm
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.
October 4th, 2009 at 12:10 am
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?
October 20th, 2009 at 6:40 am
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.
December 13th, 2009 at 4:53 am
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!
December 29th, 2009 at 7:46 am
If you set the UINavigationControllerDelegate to some random object (like the navigation view controller) and then add this method:
It will do what you expect.
February 24th, 2010 at 2:55 am
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.
April 8th, 2010 at 8:30 am
Thanks a lot. it did work well. you rescue me
April 13th, 2010 at 7:39 am
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.
May 4th, 2010 at 8:23 am
Thank you for the clear and succinct explanation. Wish I’d found this post earlier!
June 5th, 2010 at 5:29 am
You rock! You saved me days of fighting with this issue. Thanks so much for the information. Fixed my problem immediately!