我们都知道,一旦我们在View或其ViewController中放置一个插座,它就会被标记为打开,我们都知道Swift想要在初始化阶段初始化所有属性,这就是我们给任何问我们的句子第一次为什么一个出口总是与感叹号在一起。
今天我试图理解为什么来自XIB的对象无法在initWithCoder:
方法中初始化。
据我所知,XIB文件只包含有关使用XML文件结构在XIB内部绘制的对象的所有信息。因此,我们在XIB文件中看到的内容将被存档并存储到文件中。
当我们调用UINib
loadNibNamed:owner:options:
类方法时,它将取消归档先前创建的对象,查找所有属性,设置它们并将消息awakeFromNib
发送到对象...
但是由于这个感叹号上写着“在初始阶段,我无法宣称你”,我上面所说的应该是不正确的..但为什么呢?有人可以告诉我为什么Nib不能初始化,应该标记为可选?
在这里,我有一些来自Apple的文档没有帮助我https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
您的@IBOutlet
属性由UIViewController
子类引入。
说“Swift想要在初始化阶段初始化所有属性”是过分简化了。
Swift初始化规则规定子类引入的所有属性必须在调用超类初始化器之前初始化,并且Swift编译器必须能够“看到”此初始化;必须有明确的任务。这是“安全检查1”: -
安全检查1
指定的初始值设定项必须确保在委托一个超类初始化程序之前初始化其类引入的所有属性。
在几乎所有使用XIB或故事板场景的情况下,都不会覆盖init(coder:)
,因此编译器可以确定您没有为这些属性显式指定值。
如果您确实覆盖了初始化器并分配了值(或者即使您在声明属性时只是简单地指定了默认值),那么您可以将它们设置为普通属性而不是隐式解包的选项,但这会有点无意义,因为您几乎会立即覆盖加载XIB时的那些值。
隐式解包的可选项不会说“在初始阶段我无法初始化你”;它更像是“我知道它看起来没有被初始化,但在运行时它将是。相信我”(严格来说它只是声明一个可选的,允许是nil
,所以编译器不抱怨它没有初始化,但是只要它被引用,就会隐式强制展开属性 - 因此名称,“隐式解包可选”)。
这适用于@IBOutlet
s,因为加载过程使用Key Value Coding在运行时分配值。
这就是为什么,如果你删除@IBOutlet
但忘记更新XIB / Storyboard,你会得到一个运行时异常,说明你的类“不符合xxx的键/值”。
以这种方式使用隐式展开的选项通常被认为是可接受的,因为您将很快发现在测试期间是否存在连接问题(因为您的应用程序将以“意外为零”崩溃)并且它可以节省大量条件展开。