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

发布于 2024-12-08 15:10:10 字数 710 浏览 0 评论 0原文

这是球场。

  • 我有一个 UIViewController 子类,它在 viewWillAppear 和 viewDidAppear 方法中执行某些操作。
  • 我想将此视图控制器嵌套在 UINavigationViewController 中。
  • 根据视图层次结构的复杂性,控制器的两个方法 viewWillAppearviewDidAppear 可能不会被调用。

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

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

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

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

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 viewWillAppear and viewDidAppear of my controller may not be called.

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 viewWillAppear and viewDidAppear methods of the TabBarController are called but not those of the custom UIViewControllers nested under the UINavigationViewControllers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

渡你暖光 2024-12-15 15:10:10

注意:这是在 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

以下是代码的更改方式。

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

@interface CustomViewController : UIViewController <UINavigationControllerDelegate>

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

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

  • 当 UINavigationController 即将显示视图控制器本身时,
  • 当 UINavigationController 即将显示另一个视图控制器时, 将调用 viewWillAppear 方法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];
    }
}

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

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

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

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

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.

Original Answer
When 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?

The answer...

Use the UINavigationControllerDelegate methods

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:

@interface CustomViewController : UIViewController <UINavigationControllerDelegate>

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

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:

  • 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.

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:

- (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.

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

顾北清歌寒 2024-12-15 15:10:10

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

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

鱼窥荷 2024-12-15 15:10:10

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

我最近遇到了一个问题,即在复制/粘贴后不再调用 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 :(
}

请在此分享此发现,以防人们遇到同样的问题。

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

I ran into an issue lately that viewDidAppear is no longer called after some copy/paste. After reading @Yar's answer, I did a search on viewDidAppear in my code and found that [super viewDidAppear:animated]; was mistakenly called in 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.

倚栏听风 2024-12-15 15:10:10

应该按如下方式完成:

请参阅(*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;
}

it should be done as follows:

See (*1) edit

- (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;
}
情绪操控生活 2024-12-15 15:10:10

上述解决方案对我不起作用。我的情况是嵌套在复杂的 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.

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:

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.
甜心 2024-12-15 15:10:10

我的问题仅与此类似。

自定义TabBarController ->自定义UINavigationController -> CustomUINavigationController 和 RootViewController 的RootViewcontroller

viewWillAppear 不会被调用,除非您切换到另一个选项卡并返回。

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

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

我为这个小错误奋斗了一天多。

My problem was similar to this only.

CustomTabBarController -> CustomUINavigationController -> RootViewcontroller

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

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

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文