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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7674958/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:45:29  来源:igfitidea点击:

When using a UINavigationController the viewWillAppear or viewDidAppear methods of my controller are not called

iphoneiosuiviewcontrolleruinavigationcontroller

提问by MiKL

Here is the pitch.

这里是球场。

  • I have a UIViewController subclass which does something in its viewWillAppear and viewDidAppear methods.
  • I want to nest this view controller in a UINavigationViewController.
  • Depending on the view hierarchy complexity the two methods viewWillAppearand viewDidAppearof my controller may not be called.
  • 我有一个 UIViewController 子类,它在其 viewWillAppear 和 viewDidAppear 方法中执行某些操作。
  • 我想将此视图控制器嵌套在 UINavigationViewController 中。
  • 根据视图层次结构的复杂性,可能不会调用这两种方法viewWillAppearviewDidAppear我的控制器。

What should I do then to make sure these two methods are always called regardless of my view hierarchy?

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

Example of a "complex" view hierarchy:

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

UIViewController subclass containing a UITabBarController
     |_ Each tab containing a UINavigationViewController
         |_ Each UINavigationController controller containing a custom UIViewController

When you present the TabBarController as a modal view the viewWillAppearand viewDidAppearmethods of the TabBarController are called but not those of the custom UIViewControllers nested under the UINavigationViewControllers.

当您将 TabBarController 作为模态视图呈现时,将调用 TabBarController的viewWillAppearviewDidAppear方法,但不会调用嵌套在 UINavigationViewController 下的自定义 UIViewController 的方法。

回答by MiKL

NOTE: this was written in 2013. Changes to the way iOS handles view hierarchies nowadays may render this solution useless and/or dangerous. So use at your own risk.

注意:这是在 2013 年编写的。如今对 iOS 处理视图层次结构方式的更改可能会使此解决方案变得无用和/或危险。所以使用风险自负。

Original AnswerWhen nesting a custom UIViewController under a UINavigationController the methods viewWillAppear and viewDidAppear of the custom viewController may not be called depending on the complexity of your view controller hierarchy (think modal views, navigation controller inside tab view controller...). So if you find yourself in this situation what can you do to ensure these two methods are called?

原始答案当在 UINavigationController 下嵌套自定义 UIViewController 时,可能不会调用自定义 viewController 的 viewWillAppear 和 viewDidAppear 方法,具体取决于您的视图控制器层次结构的复杂性(想想模态视图、选项卡视图控制器内的导航控制器......)。那么如果你发现自己处于这种情况,你能做些什么来确保这两个方法被调用?

The answer...

答案...

Use the UINavigationControllerDelegate methods

使用 UINavigationControllerDelegate 方法

This is a very elegant method to implement for it does not rely on any assumptions regarding when the controller will be loaded by the navigation controller.

这是一种非常优雅的实现方法,因为它不依赖于有关导航控制器何时加载控制器的任何假设。

There are two methods available:

有两种方法可用:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated

Here is how the code would change.

以下是代码将如何更改。

You need to declare that your CustomViewController implements the UINavigationControllerDelegate protocol:

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

@interface CustomViewController : UIViewController <UINavigationControllerDelegate>

You need to set your CustomViewController as the delegate of the UINavigationController where you initialize it.

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

Last you must also add your custom implementation of the UINavigationControllerDelegate methods to your CustomViewController class implementation. For instance you can implement the navigationController:willShowViewController:animated:method so that:

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

  • when the UINavigationController is about to show the view controller itself your viewWillAppear method is called
  • when the UINavigationController is about to show another view controller the delegate of the UINavigationController is set to this other view controller, provided that this view controller implements the UINavigationViewControllerDelegate method.
  • 当 UINavigationController 即将显示视图控制器本身时,您的 viewWillAppear 方法被调用
  • 当 UINavigationController 即将显示另一个视图控制器时,UINavigationController 的委托被设置为这个另一个视图控制器,前提是这个视图控制器实现了 UINavigationViewControllerDelegate 方法。

List item

项目清单

- (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];
    }
}

And the navigationController:didShowViewController:animated:can be implemented simply as follows:

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

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

The benefit of this approach is really that you solely rely on the way the UINavigationViewController is supposed to work and you make your calls just at the right time. It also allows you to pass the delegation around as you move up and down the navigation controller hierarchy right before the viewWillAppear method is called.

这种方法的好处实际上是您完全依赖 UINavigationViewController 应该工作的方式,并且您可以在正确的时间进行调用。它还允许您在调用 viewWillAppear 方法之前在导航控制器层次结构中上下移动时传递委托。

Again for simple hierarchy this may not be required. But if you ever find yourself in a situation where your viewWillAppearand viewDidAppearmethods are not called you now know what to do...

同样对于简单的层次结构,这可能不是必需的。但是,如果您发现自己处于未调用viewWillAppearviewDidAppear方法的情况,那么您现在知道该怎么做...

回答by Dan Rosenstark

One reason this will happen is if you override viewDidAppear:in your UINavigationControllersubclass and don't call [super viewDidAppear:animated];...

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

回答by Jingshao Chen

It is 2015 now and you probably don't need to use the UINavigationControllerDelegate methods as in the accepted answer. Just check carefullyyour code if you have any typo or copy/paste error.

现在是 2015 年,您可能不需要像接受的答案那样使用 UINavigationControllerDelegate 方法。如果您有任何拼写错误或复制/粘贴错误,请仔细检查您的代码。

I ran into an issue lately that viewDidAppearis no longer called after some copy/paste. After reading @Yar's answer, I did a search on viewDidAppearin my code and found that [super viewDidAppear:animated];was mistakenly called in viewWillAppear:

我最近遇到了一个问题,viewDidAppear在复制/粘贴后不再调用。阅读@Yar 的回答后,我viewDidAppear在我的代码中进行了搜索,发现它[super viewDidAppear:animated];被错误地调用了viewWillAppear

-(void)viewWillAppear:(BOOL)animated
{
   [super viewDidAppear:animated];
   //...      ^^^ 
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    // this is never called :(
}

Just share this finding here in case people run into same issue.

只需在此处分享此发现,以防人们遇到相同的问题。

回答by Ching-Lan Chen

The above solution not works for me. My case is the custom view controller nested under a complex UINavigationController not gets called viewWillAppear and viewDidAppear. Use below in custom view controller:

上述解决方案对我不起作用。我的情况是嵌套在复杂 UINavigationController 下的自定义视图控制器不会被称为 viewWillAppear 和 viewDidAppear。在自定义视图控制器中使用以下内容:

beginAppearanceTransition(true, animated: animated)  // Tells a child controller its appearance is about to change. Do not invoke viewWillAppear(_:), viewWillDisappear(_:), viewDidAppear(_:), or viewDidDisappear(_:) directly.
endAppearanceTransition() // Tells a child controller its appearance has changed.

回答by YSR fan

My problem was similar to this only.

我的问题仅与此类似。

CustomTabBarController -> CustomUINavigationController -> RootViewcontroller

CustomTabBarController -> CustomUINavigationController -> RootViewcontroller

viewWillAppear of CustomUINavigationController and RootViewController are not getting called unless you switched to another tab and come back.

除非您切换到另一个选项卡并返回,否则不会调用 CustomUINavigationController 和 RootViewController 的 viewWillAppear。

The solution is call super.viewWillAppear(animated: true)

解决方法是调用 super.viewWillAppear(animated: true)

override func viewWillAppear(_ animated: Bool) {
    **super.viewWillAppear(true)**
}

I struggled for more than a day for this small mistake.

为了这个小错误,我挣扎了一天多。

回答by mrd3650

it should be done as follows:

应按如下方式进行:

See (*1) edit

见 (*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;
}