使用UINavigationController时,不调用我的控制器的viewWillAppear或viewDidAppear方法

MiK*_*iKL 13 iphone uiviewcontroller uinavigationcontroller ios

这是球场.

  • 我有一个UIViewController子类,它在viewWillAppear和viewDidAppear方法中做了一些事情.
  • 我想将此视图控制器嵌套在UINavigationViewController中.
  • 根据视图层次结构的复杂性,可能不会调用两个方法viewWillAppearviewDidAppear我的控制器.

那么我应该怎么做以确保无论我的视图层次结构如何都始终调用这两个方法?

"复杂"视图层次结构的示例:

UIViewController subclass containing a UITabBarController
     |_ Each tab containing a UINavigationViewController
         |_ Each UINavigationController controller containing a custom UIViewController
Run Code Online (Sandbox Code Playgroud)

当您将TabBarController作为模态视图呈现时,将调用TabBarController的方法viewWillAppearviewDidAppear方法,而不是嵌套在UINavigationViewControllers下的自定义UIViewControllers的方法.

MiK*_*iKL 21

注意:这是在2013年编写的.现在iOS处理视图层次结构的方式的改变可能使该解决方案无用和/或危险.因此使用风险自负.

原始答案 在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
Run Code Online (Sandbox Code Playgroud)

以下是代码的更改方式.

您需要声明您的CustomViewController实现UINavigationControllerDelegate协议:

@interface CustomViewController : UIViewController <UINavigationControllerDelegate>
Run Code Online (Sandbox Code Playgroud)

您需要将CustomViewController设置为初始化它的UINavigationController的委托.

最后,您还必须将UINavigationControllerDelegate方法的自定义实现添加到CustomViewController类实现中.例如,您可以实现该navigationController:willShowViewController:animated:方法,以便:

  • 当UINavigationController即将显示视图控制器本身时,将调用viewWillAppear方法
  • 当UINavigationController即将显示另一个视图控制器时,UINavigationController的委托被设置为该另一个视图控制器,前提是该视图控制器实现UINavigationViewControllerDelegate方法.

项目清单

- (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];
    }
}
Run Code Online (Sandbox Code Playgroud)

并且navigationController:didShowViewController:animated:可以简单地实现如下:

- (void)navigationController:(UINavigationController *)navigationController 
       didShowViewController:(UIViewController *)viewController 
                    animated:(BOOL)animated
{
    if ([viewController isEqual:self]) {
        [self viewDidAppear:animated];
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的好处实际上是你完全依赖于UINavigationViewController应该工作的方式,并且你在恰当的时间拨打电话.它还允许您在调用viewWillAppear方法之前向上和向下移动导航控制器层次结构时传递委托.

同样对于简单的层次结构,可能不需要这样.但如果你发现自己处于不调用你viewWillAppearviewDidAppear方法的境地,你现在知道该怎么做......


Dan*_*ark 8

这种情况发生的一个原因是你viewDidAppear:在你的UINavigationController子类中重写并且不调用[super viewDidAppear:animated];...