为什么 outlet 不能在 initWithCoder 中初始化?

Why outlet cannot be init within initWithCoder?

我们都知道,一旦我们将出口放入视图或其 ViewController 中,它就会被标记为未包装并且我们都知道 Swift 想要初始化其中的所有属性初始化阶段,这是我们给第一次问我们为什么出口总是伴随感叹号的人的一句话。

今天我试图理解为什么来自 XIB 的对象不能在 initWithCoder: 方法中初始化。

据我所知,XIB 文件仅包含有关使用 XML 文件结构在 XIB 内部绘制的对象的所有信息。 所以我们在 XIB 文件中看到的内容将被存档并存储到文件中。

当我们调用 UINib loadNibNamed:owner:options: class 方法时,它会取消归档之前创建的对象,查找所有属性,设置它们并发送消息 awakeFromNib 到对象...

但是由于那个感叹号 "During the init phase I'm not able to init you" 我上面说的应该是不正确的..但是为什么呢? 有人能告诉我为什么 Nib 不能初始化并且应该标记为可选吗?

这里有一些 Apple 的文档对我没有帮助 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html

您的 @IBOutlet 属性由您的 UIViewController 子 class 引入。

说“Swift 想要在初始化阶段初始化所有属性”有点过于简单化了。

Swift 初始化规则声明由 subclass 引入的所有属性必须在调用 superclass 初始化器之前初始化,并且 Swift 编译器必须能够“看到”这个初始化;必须有明确的分配。这是“安全检查 1”:-

Safety check 1

A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

在几乎所有使用 XIB 或情节提要场景的情况下,您都不会覆盖 init(coder:),因此编译器可以确定您没有明确分配值 这些属性。

如果您确实重写了初始化程序并分配了值(或者即使您在声明属性时只是简单地分配了默认值),那么您可以使它们成为普通属性而不是隐式展开可选值,但这有点毫无意义,因为当加载 XIB 时,您几乎会立即覆盖这些值。

一个隐式展开的可选项不会说“在初始化阶段我不能初始化你”;它更像是“我知道它看起来没有被初始化,但在运行时它会被初始化。相信我”(严格来说它只是声明一个可选的,它被允许是 nil,所以编译器不会抱怨它没有被初始化,而是隐式地强制解包 属性 每当它被引用时——因此得名,“隐式解包可选”)。

这适用于 @IBOutlet 秒,因为加载过程使用 Key Value Coding 在运行时分配值。

这就是为什么如果您删除 @IBOutlet 但忘记更新 XIB/Storyboard 您会收到运行时异常,指出您的 class “不是 key/value 符合 xxx".

通常认为以这种方式使用隐式解包选项是可以接受的,因为您会很快发现在测试期间是否有连接问题(因为您的应用程序会因“意外的 nil”而崩溃)并且它会节省很多条件展开。