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