0

我遇到了一个有趣的问题。我有一个视图控制器:

LoginViewController *viewController = [LoginViewController alloc] init];

在方法中initWithNibName:bundle:awakeFromNib我有一些初始化代码。LoginViewController 有一个名为 LoginViewController.xib 的 .xib 文件。

但是,针对 iOS 9 构建,这些方法永远不会被调用,代码也永远不会运行。但是,除非我LoginViewController这样初始化:

LoginViewController *viewController = [LoginViewController alloc] initWithNibName:nil bundle:nil];

然后代码运行,它工作得很好。似乎正在加载 .xib 文件,但initWithNibName:bundle:从未awakeFromNib调用过。

有谁知道为什么在awakeFromNib存在相应的 .xib 时默认不调用 iOS 9 中的原因?这个问题在 iOS 8 中不存在(awakeFromNib即使我只是用来init初始化我的视图控制器也被调用)。

4

2 回答 2

2

iOS 9 发行说明中描述了视图控制器 nib 加载行为的更改 :

如果使用 nil nibName 值初始化,UIViewController.nibName 总是寻找与视图控制器的类具有相似名称的 nib,如果 loadView 没有被覆盖,则默认为该值。在 iOS 9 之前,用 Swift 编写的 UIViewController 的子类需要它们对应的 nib 文件名包含模块前缀。

为了提高重构时的灵活性,您可以在 iOS 9 中运行的代码中从 nib 文件名中省略模块名称。 UIViewController.nibName 仍然更喜欢包含模块前缀的名称,但如果 nib 则回退到非限定名称未找到具有完全限定名称的。

此外,UIViewController 的类文档指出:

如果为 nibName 参数指定 nil 并且不覆盖 loadView 方法,则视图控制器会按照 nibName 属性中的说明搜索 nib 文件。

如果您正在执行初始化,-initWithNibNamed:bundle:最好改为在-initWithCoder:和/或-loadView(取决于您在做什么)中执行初始化。-awakeFromNib仍然适合通常应该去那里的东西。

-initWithNibNamed:bundle:从您的问题看来: -awakeFromNib当视图控制器子类使用-init. --initWithNibNamed:bundle:并且在视图控制器子类被实例化时被awakeFromNib 调用-initWithNibNamed:bundle:

这有点好奇。-initWithNibNamed:bundle:是指定的初始化程序,因此-init应该使用 nil 参数调用它以触发上述行为。使用Hopper在 iOS 9 上快速反汇编 UIKit表明情况仍然如此。

如果您覆盖-loadView -initWithNibName:bundle:不会尝试为您加载笔尖 - 通过覆盖-loadView您选择自己执行此操作。如果您正在覆盖-loadView(即使您调用 super),请将其删除,并且 nib 应该会加载。-awakeFromNib不会被调用,因为视图控制器是 nib 的所有者 - 只有孩子才能获得该方法调用。如果它是故事板的一部分,它将被调用。-awakeAfterUsingCoder:但是,将被调用,并且可能是一个更好的地方来完成您正在尝试的工作-awakeFromNib

我将您的问题简化为一个简单的测试用例,并在 iOS 9 和 iOS 8.4 SDK 上确认了这种行为。

于 2015-09-26T00:30:17.690 回答
0

我有同样的问题。出于某种原因,我的方法 awakeFromNib-awakeFromNib没有被调用。我知道这不是一个好习惯,但如果你关心你的代码,你可以使用NSNotificationCenter来解决这个问题。

于 2015-10-05T21:55:44.747 回答