initWithNibName、awakeFromNib 和 viewDidLoad 的描述?

Posted

技术标签:

【中文标题】initWithNibName、awakeFromNib 和 viewDidLoad 的描述?【英文标题】:Description of initWithNibName, awakeFromNib and viewDidLoad? 【发布时间】:2009-08-06 16:23:49 【问题描述】:

是否对initWithNibNameawakeFromNibviewDidLoad 进行了很好的概述,列出了使用它们的最佳方式并准确描述了它们的作用?我觉得这些非常令人困惑。在使用 View Controller 生成的模板中,关于 initWithNibName 的评论说:

指定的初始化器。覆盖以执行加载视图之前所需的设置。

除了这个方法似乎永远不会被调用(我正在使用 IB 来设置视图控制器)。那我应该改用awakeFromNib 还是viewDidLoad 来初始化?

【问题讨论】:

您的问题是关于 iPhone 还是 Mac?这是一个或另一个; AppKit 和 UIKit 不可互换。 我的问题是关于 iPhone 的。 【参考方案1】:

我刚刚完成了一些关于这个主题的研究,所以我想分享一些我学到的东西。

    在 iPhone 的视图中使用 awakeFromNib 没有任何问题。见this Apple Dev document。

    initWithCoder 不是在从 NIB 文件加载视图时进行初始化的好地方,因为同一 NIB 文件中的其他项目可能已经或可能没有被初始化观点。因此,例如,出口可能仍然为零。在调用awakeFromNib 时,保证同一个NIB 文件中的所有项目都被正确初始化。

    viewDidLoad 在 viewController 中进行设置工作的好地方。

那么为什么要在视图中使用awakeFromNib?我能想到的一个原因是,如果在视图被初始化并连接到 NIB 文件中的其他对象之后,您有想要做的事情,但您只想将其封装在视图中。这减少了与视图控制器的链接。

【讨论】:

使用 awakeFromNib 的另一个原因是,如果您使用视图或控件和按钮等子类,而没有 UIViewController。 在我的问题***.com/questions/5895262/why-need-awakefromnib中转到 awakeFromNib 时,一些 IBOutlet 仍然为空@ 但是对于 UIView 子类?【参考方案2】:

如果您在 IB 中创建视图,那么您应该使用viewDidLoad。每次初始化视图以放置时都会调用它。在代码中创建视图时使用initWithNibName:。您不应该在 iPhone 的视图中使用 awakeFromNib

initWithNibName 似乎没有被调用的原因是接口构建器实际上创建了视图控制器的真实实例,然后序列化该视图。因此,当您在 IB 中创建视图控制器(基本上将其添加到您的项目中)时,IB 调用 initWithNibName,但除非您覆盖了默认的 encodeWithCoder:,否则您设置的任何瞬态变量都会当视图从笔尖加载时消失(反序列化)。这通常没问题,因为您通常希望使用特定于应用程序当前运行上下文的信息而不是预先确定的初始化程序来设置视图。

即使您以编程方式创建视图和视图控制器,您仍然可以将所有初始化放在viewDidLoad 中。这通常会更好,因为如果您的视图最终被缓存(卸载)然后返回到屏幕上,则可以再次调用 viewDidLoad 而您的初始化程序则不一定如此。例如,您以编程方式创建一个视图并将其推送到导航控制器的堆栈中——稍后视图已被覆盖并发出内存警告,因此导航控制器“卸载”您的视图但不释放对象——当视图返回(其他视图被弹出),导航控制器将再次调用viewDidLoad,以便您可以重新初始化,但不会再次调用initWithNib。请注意,这是一种罕见的情况,无论如何,大多数人的应用程序在这一点上都会因为其他原因而可怕地死掉。

【讨论】:

Jason - 谢谢 - 这真的很有帮助!所以跟进问题:我目前正在使用 awakeFromNib 和 viewWillAppear 来设置我的模型(在 awakeFromNib 中),然后使用我的模型中的信息在我的视图中设置文本(在 viewWillAppear 中)。如果我将 awakeFromNib 中的代码移动到 viewDidLoad,它是否保证在 viewWillAppear 之前运行?我需要确保设置代码在 viewWillAppear 之前运行。我只想设置一次模型(显然),那么最好的地方是哪里,以便 1)它只运行一次,2)它在 viewWillAppear 方法之前运行?谢谢! 是的,它将在 viewWillAppear 之前运行。它还会在每次加载视图时运行(例如在内存警告之后),从而使这里成为做这些事情的地方。 小心在 viewWillAppear 中添加一次初始化代码,因为每次视图可见时都会调用它。因此,如果您导航或推送另一个视图控制器,当它们返回父视图控制器时 viewWillAppear 会再次被调用。 justme 的回答比上面的回答更贴切。 "如果您在 IB 中创建视图,那么您应该使用 viewDidLoad" 请记住,如果您不使用 UIViewController,则不会调用 viewDidLoad。换句话说,如果您正在创建自己处理的视图,而无需 UIViewController 的帮助,那么您将永远不会收到 viewDidLoad 调用。也不是 viewWillAppear,viewWill....【参考方案3】:

viewDidLoad 可以被多次调用,因此它不是大多数初始化的合适位置(尽管实际上它只被调用一次,除非你正在干预) - 这就是为什么 awakeFromNib 是特殊且非常必要的:它只被调用一次。

viewDidLoad 在 UIView 上不存在 - UIView 具有 awakeFromNib 用于初始化,并且没有其他合理的选项。

在过去的六个月里,我一直很高兴地将 awakeFromNib 与故事板(应用程序的单个故事板)一起使用,完全没有任何问题,并且它在文档中指定的所有出口配置下表现完美。然后今天我把一些代码拆开并放入一个新的视图控制器和视图,但没有一个像我过去所经历的那样工作,即所有出口在 awakeFromNib 中为零。我的理论很简单——SDK 很烂,因为很容易在你的控制器/视图和类链中的某个地方做一些琐碎的事情并破坏一切。

现在我又要研究这个毫无意义的话题了,我只需要一个简单一致的地方来进行初始化。

【讨论】:

以上是关于initWithNibName、awakeFromNib 和 viewDidLoad 的描述?的主要内容,如果未能解决你的问题,请参考以下文章

卡在 initWithNibName

UIViewController 的 initWithNibName:这个设计背后的原因?

initWithNibName 是如何工作的?

iPhone:TableViewController nibName 错误,带有“initWithNibName:bundle:”

initWithNibName 没有被调用

UIViewController init 与 initWithNibName:bundle: