当使用UINavigationController时,我的控制器的viewWillAppear或viewDidAppear方法不会被调用
这是球场。
- 我有一个UIViewController子类,它在viewWillAppear和viewDidAppear方法中做了一些事情。
- 我想在UINavigationViewController中嵌套这个视图控制器。
- 根据视图层次的复杂性,我的控制器的两个方法
viewWillAppear
和viewDidAppear
可能不会被调用。
我应该怎么做才能确保这两个方法总是被调用,而不pipe我的视图层次?
“复杂”视图层次结构的示例:
UIViewController subclass containing a UITabBarController |_ Each tab containing a UINavigationViewController |_ Each UINavigationController controller containing a custom UIViewController
当您将TabBarController作为模式视图呈现时,将调用TabBarController的viewWillAppear
和viewDidAppear
方法,但不嵌套在UINavigationViewControllers下嵌套的自定义UIViewController。
注意:这是在2013年编写的。如今iOS处理视图层次结构的方式的改变可能使得这个解决scheme无用和/或危险。 所以使用风险自负。
原始解决scheme在UINavigationController下嵌套一个自定义UIViewController时,可能不会调用自定义viewController的viewWillAppear和viewDidAppear,这取决于视图控制器层次结构的复杂性(认为模态视图,导航控制器内部的标签视图控制器…)。 所以如果你发现自己处在这种情况下,你可以做什么来确保这两种方法被称为?
答案…
使用UINavigationControllerDelegate方法
这是一个非常优雅的实现方法,它不依赖于控制器何时将被导航控制器加载的任何假设。
有两种方法可用:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
这是代码将如何改变。
你需要声明你的CustomViewController实现了UINavigationControllerDelegate协议:
@interface CustomViewController : UIViewController <UINavigationControllerDelegate>
您需要将您的CustomViewController设置为初始化它的UINavigationController的委托。
最后,您还必须将您的UINavigationControllerDelegate方法的自定义实现添加到您的CustomViewController类实现中。 例如,您可以实现navigationController:willShowViewController:animated:
方法,以便:
- 当UINavigationController即将显示视图控制器本身时,您的viewWillAppear方法被调用
- 当UINavigationController即将显示另一个视图控制器时,如果此视图控制器实现UINavigationViewControllerDelegate方法,则将UINavigationController的委托设置为此其他视图控制器。
项目清单
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([viewController isEqual:self]) { [viewController viewWillAppear:animated]; } else if ([viewController conformsToProtocol:@protocol(UINavigationControllerDelegate)]){ // Set the navigation controller delegate to the passed-in view controller and call the UINavigationViewControllerDelegate method on the new delegate. [navigationController setDelegate:(id<UINavigationControllerDelegate>)viewController]; [[navigationController delegate] navigationController:navigationController willShowViewController:viewController animated:YES]; } }
而navigationController:didShowViewController:animated:
可以简单实现如下:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([viewController isEqual:self]) { [self viewDidAppear:animated]; } }
这种方法的好处在于,您完全依赖于UINavigationViewController应该工作的方式,而且您只需在正确的时间打电话。 它还允许您在调用viewWillAppear方法之前,在导航控制器层次结构中上下移动代理团队。
再次为简单的层次结构,这可能不是必需的。 但是,如果您发现自己处于viewWillAppear
和viewDidAppear
方法未被调用的状态,则您现在知道该怎么做…
这将发生的一个原因是,如果你重写viewDidAppear:
在你的UINavigationController
子类中,不要调用[super viewDidAppear:animated];
…
现在是2015年,您可能不需要像接受的答案中那样使用UINavigationControllerDelegate方法。 如果您有任何错字或复制/粘贴错误,请仔细检查您的代码。
最近我碰到一个问题,那就是viewDidAppear
在复制/粘贴后不再被调用。 阅读@亚尔的回答后,我做了一个viewDidAppear
在我的代码search,发现[super viewDidAppear:animated];
被错误地称为viewWillAppear
:
-(void)viewWillAppear:(BOOL)animated { [super viewDidAppear:animated]; //... ^^^ } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // this is never called :( }
只要在这里分享这个发现,以防人们遇到同样的问题。
应该按照如下方式进行:
请参阅(* 1)编辑
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { CustomViewController *controller = [[CustomViewController alloc] initWithNibName:nil bundle:nil]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; [controller release]; self.window.rootViewController = navController; //(*1) [self.window makeKeyAndVisible]; [navController release]; return YES; }