为什么 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”而崩溃)并且它会节省很多条件展开。
我们都知道,一旦我们将出口放入视图或其 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”而崩溃)并且它会节省很多条件展开。