viewWillAppear和viewDidAppear没有被调用,不触发

39

症状:我的UIViewController中没有调用viewWillAppear、viewDidAppear方法。

原因:将UINavigationController或UITabBarController(在我这种情况下)嵌入到UIViewController中,会以某种方式干扰这些方法的调用。

解决方案:在包含上述UINavigationController / UITabBarController的UIViewController中手动调用它们。

例如(假设projectNavigationController是您的UINavigationController):

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [projectNavigationController viewWillAppear:animated];
}
-(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [projectNavigationController viewWillDisappear:animated]; }
-(void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [projectNavigationController viewDidAppear:animated]; }
-(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [projectNavigationController viewDidDisappear:animated]; }

在我的情况下,我有一个内部的UITabBarController,并相应地调用了这些方法,所有问题都得到了解决。

(解决方案归功于:http://davidebenini.it/2009/01/03/viewwillappear-not-being-called-inside-a-uinavigationcontroller/


1
只是因为我好奇...:你为什么要将一个标签栏控制器包装到另一个视图控制器中呢?:) 在大多数情况下,它们是视图(控制器)层次结构的根... - Toastor
2个回答

11
我不同意@St3fan的观点,我会使用UIKit作为反例。
然而,嵌入控制器是否合理应该受到明智的UI设计原则的指导。
最简单的反例是在UITabBarController中嵌入UINavigationController。这些出现在各种地方。仅仅从我的记忆中,iPhone上的iPod应用程序和Phone应用程序中的联系人都是如此。
我很好奇他们对视图做了什么(添加到“超级控制器”视图还是UIWindow)。我敢肯定我会发现子控制器视图是超级控制器视图在视图层次结构中的后代,这与St3fan的建议相反。
我很快就创建了一个基于UITabBarController的iPhone应用程序,并使用InterfaceBuilder将所有内容连接起来,其中一个选项卡是具有普通的UIViewController作为其根视图控制器的UINavigationController,第二个选项卡是普通的UIViewController,以便我稍后单击第二个选项卡。
加入一些NSLog语句来输出我们看到的各种控制器的UIView,结果如下:
tabBarController.view = <UILayoutContainerView: 0x5b0dc80; ...
navigationController.view = <UILayoutContainerView: 0x59469a0; ...
rootViewController.view = <UIView: 0x594bb70; ...
Superview: <UIViewControllerWrapperView: 0x594cc90; ...
Superview: <UINavigationTransitionView: 0x594a420; ...
Superview: <UILayoutContainerView: 0x59469a0; ... // navigationController.view
Superview: <UIViewControllerWrapperView: 0x594b430; ...
Superview: <UITransitionView: 0x5b0e110; ...
Superview: <UILayoutContainerView: 0x5b0dc80; ... // tabBarController.view
Superview: <UIWindow: 0x5942a30; ...

以 "Superview" 为前缀的行是从 rootViewController.view 的 superview 链向上遍历直到遇到 nil 所输出的结果。

然后,在几个 viewDidDisappear 被调用的情况下,快速查看调用堆栈中的一些位置,这些情况下是在根视图控制器上调用。

首先,当因将新控制器推入堆栈而在根控制器上调用 viewDidDisappear 时的调用堆栈如下:

-[RootController viewDidDisappear:]
-[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:]
...

其次,在最上层的UITabBarController中选择另一个选项卡时的调用栈:

-[RootController viewDidDisappear:]
-[UINavigationController viewDidDisappear:]
-[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:]

因此,在所有情况下,似乎苹果公司决定控制器应该调用其嵌入子控制器上的各种viewDidAppear等方法,并且视图应类似地嵌入。如果我们要以UIKit设计为良好的指导,我认为OP说得很对。


有趣的分析,imaginaryboy。我欣赏你的观点,St3fan。在典型的设置中,UITabBarController(它有自己的导航控制器和视图控制器)被添加到窗口中。这一点很容易看出来。然而,在我的情况下稍有不同。在我的情况下,用户通过模态方式进入应用程序的特定模式。在这种另外的模式下,与用户最初看到的那个不同,有一个不同的UITabBarController。也许我可以调用应用委托将新的UITabBarController添加到窗口中(?),但是将其添加到模态UIViewController中更容易一些。 - pschang

0

我刚刚看到了同样的情况。早些时候,由表格单元格选择触发的界面生成器segue停止工作了,经过一番挖掘代码的努力后,我手动设置了它,从表视图委托中的单元格选择覆盖调用。

后来,我在被调用的视图控制器中进行了一些布局更改,并发现viewDidAppear没有被调用,就像上面所描述的那样。调试输出引用了“嵌套推操作”之类的内容,因为我在我的手动推操作中有一个大的注释

#warning I SHOULD NOT HAVE TO DO THIS!!

我断点了segue代码,确实,IB segue现在正在工作,而是在表格单元格选择代码中的手动操作导致了被调用视图中的委托调用出现问题。我删除了手动代码,现在一切都正常了。

似乎很奇怪的是,在推送视图之后会调用单元格选择代码。我必须使用协议和委托来获取调用者中所选单元格的索引路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接