viewWillAppear and viewDidAppear not being called in your UINavigationController or UITabBarController - SOLUTION
Yesterday I ran into a problem. I had a UITableView shown via NavigationController in one of my tabs in TabBarController. It took me quite a while of googling to come up with a solution for this so I bring it to you.
First you need to setup your root view as a UINavigationControllerDelegate.
@interface RootViewController : UIViewController <UINavigationControllerDelegate> { IBOutlet UINavigationController* navigationController; } @property (nonatomic, retain) UINavigationController* navigationController; @end
Somewhere in the implementation then (I do it in the viewDidLoad method) assign RootViewController as a delegate of navigationController
- (void)viewDidLoad { navigationController.delegate = self; [super viewDidLoad]; }
Finally you need to add two methods to your RootViewController so it conforms to the UINavigationControllerDelegate protocol. This will secure that viewWillAppear and viewDiDAppear gets called every time you switch views with your NavigationController
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [viewController viewWillAppear:animated]; } - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [viewController viewDidAppear:animated]; }
What took me more time to figure out is when you have UITabBarController a run into a similar problem. The solution is technically the same as for NavigationController. You need to have a <UITabBarControllerDelegate>, usually it would be your ApplicationDelegate. Then you simply need to add a method to this delegate which will secure that everytime you switch tabs the appropriate message is sent to the View that appears.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { [viewController viewWillAppear:NO]; }
Obviously you need to set the class as a delegate of the tabBarController somewhere, so you need something like this (you don't have to assign it in didFinishLaunchingWithOptions if your tabBarController delegate is something else then you application delegate):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.tabBarController.delegate = self; [self.window addSubview:tabBarController.view]; [self.window makeKeyAndVisible]; return YES; }
And the final part, what to do if you have a NavigationController in a tab of TabBarController? Surprisingly you need to follow what I have done above and then you need to add two simple methods to you RootViewControler like this:
- (void)viewWillAppear:(BOOL)animated { [navigationController viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [navigationController viewDidAppear:animated]; }
It secures that message will be sent to your navigationController whenever RootViewController (the one in the tab) is switched to. NavigationController then passes the message to whatever view is on top and makes it fire viewWillAppear or viewDidAppear method.
I hope you found this useful if you found yourself struggling with viewDid/WillAppear methods not getting called in your views in your NavigationController or TabBarController.