关于 viewController 的“viewDidLoad”和“viewWillAppear”方法

Posted

技术标签:

【中文标题】关于 viewController 的“viewDidLoad”和“viewWillAppear”方法【英文标题】:About viewController's "viewDidLoad" and "viewWillAppear" methods 【发布时间】:2013-06-28 10:02:15 【问题描述】:

我有一个关于上述两种方法的问题,因为在我的测试中我没有明确它们被调用的顺序。我认为,首先,viewDidLoad 在第一次加载 viewController 时调用(如名称所示),并且在 init 方法之后立即调用。然后,我认为一旦viewDidLoad 返回,viewWillAppear 就会被调用。如果你显示另一个viewController,然后你返回到这个,那么它应该已经被加载并且只会调用viewWillAppear

但是,在开发过程中,我给人的印象是调用viewDidLoadviewWillAppear 时没有顺序......我在Apple 的文档中找不到这个生命周期的明确描述,这实际上是如何工作的?

谢谢!

【问题讨论】:

"viewDidLoad 在第一次加载 viewController 时被调用(顾名思义)" - 它也让我困惑了很长时间。视图控制器和它的视图是不同的东西。这是您必须了解的有关视图控制器的最重要(也是基本)的事情之一。 【参考方案1】:

我想补充一下 Caleb 的回答:不要混淆视图控制器和视图!名称viewDidLoad 清楚地表明该方法是在view 加载后调用的。执行加载的是视图控制器。

关于视图生命周期和消息发送顺序的一些提示:

不是 Apple 官方文档,但我发现 this diagram 非常有用,因为它几乎包含了 UIViewController 的所有生命周期覆盖。 在 Apple 的“视图控制器编程指南”中的 Resource Management in View Controllers 部分中,有一个流程图描述了视图最初是如何加载的。它解释了loadViewviewDidLoad,还结合了故事板。 Apple 的“视图控制器编程指南”中的 Responding to Display-Related Notifications 部分解释了如何响应视图的出现和消失(viewWillAppear: 等) 如果您计划实现容器视图控制器:UIViewController class reference 很好地概述了您的子类需要如何发送消息。

我停在这里。您可以通过谷歌搜索“uiviewcontroller 生命周期”自行查找更多内容。

【讨论】:

UIViewController lifecycle diagram 太棒了。感谢您的链接。 值得注意的是,viewWillUnload 在 ios 6 中已被弃用(“视图不再在内存不足的情况下被清除,因此永远不会调用此方法”)。生命周期图的左下部分不适用于现代 iOS 应用程序。不过,图表的其余部分非常有用,谢谢!【参考方案2】:

-viewDidLoad 在控制器加载其视图时调用,这不一定是在初始化之后。视图控制器在需要它们之前不会加载它们的视图,无论是为了显示还是出于任何其他原因。

-viewWillAppear 在视图显示之前被调用。这将在-viewDidLoad 之后,但您不知道具体过了多久。每次显示视图时都会调用-viewWillAppear-viewDidLoad 只会在视图在某个时刻被卸载(例如didReceiveMemoryWarning)时被第二次调用。现在这很不寻常,但它可能会发生。

或者如果 viewController 设置为nil,这通常会在视图控制器被踢出导航堆栈时发生,因此下次将其带到导航堆栈时需要再次调用-viewDidLoad

【讨论】:

另外,当调用 viewDidLoad 时,您可能在 Interface Builder 中设置的所有 Outlets 都已连接。【参考方案3】:

我认为,首先, viewDidLoad 在 vi​​ewController 被调用 首次加载(顾名思义),并在 init 方法之后立即加载

没有。该名称表示控制器的view 已加载(而不是控制器本身)。实际上,文档声明此方法将在视图层次结构加载到内存后被调用(例如通过 loadView 或通过 nib)。

然后,我认为一旦 viewDidLoad 返回, viewWillAppear 是 叫

再次,不。 loadView(因此viewDidLoad)方法将在第一次访问view 属性时被调用,并且是nil(当您初始化控制器时就是这种情况)。想想这个简单的场景:

MyViewController *vc = [[MyViewController alloc] init];
UIView *view = vc.view; // <= loadView & viewDidLoad will fire but it certainly didn't appear...

但是,在开发过程中,我给人的印象是没有顺序 当调用 viewDidLoad 和 viewWillAppear...

嗯,有一个命令。我们确信viewWillAppear 将始终在viewDidLoad 之后被调用(当然,如果它们都被调用)。

【讨论】:

那么,关键是如果两个方法都被调用是有顺序的,但是viewDidLoad不一定要在viewWillAppear被调用之前返回? 关键是这些方法没有以任何方式“链接”。 viewDidLoad 是关于将层次结构加载到内存中,而 viewWillAppear 在视图即将添加到层次结构中时调用(用于演示)。 viewDidLoad总是viewWillAppear之前返回。【参考方案4】:

正如你所说,ViewDidLoad 只在加载视图后调用一次。所以我们可以在viewDidLoad中初始化实例。它主要用于初始化。

viewWillAppear 将在我们到达该视图时调用。因此,如果 UI 有任何变化,我们可以在 viewWillAppear 中完成。

【讨论】:

【参考方案5】:

我跟踪了所有这些调用的时间:http://thecodist.com/article/ios_arc_storyboards_and_uiviewcontroller_trace

【讨论】:

以上是关于关于 viewController 的“viewDidLoad”和“viewWillAppear”方法的主要内容,如果未能解决你的问题,请参考以下文章

xcode 不值钱的动画UIButton

Interface Builder 将控制出口设置为零——为啥?

关于 viewController 的“viewDidLoad”和“viewWillAppear”方法

关于obj-c的几个问题(delegate、viewController、simulator)

关于使用多态显示 iPhone/iPad ViewControllers

关于如何修复错误“找不到名为 viewcontroller 的类的任何信息”的建议