你正在尝试实施init()
— 一个不可失败的初始化器 — 通过委托给init?(nibName:bundle:)
,这是一个失败的初始化器。这不起作用:如果super.init
调用失败,你会留下一个未初始化的实例,这是 Swift 不允许的。
或者换句话说,使用可失败初始化程序的结果是可选的,并且您不能使用可选值来代替非可选值。在类初始化和继承的情况下,您不能替换非可选的self
对于可选的 - 您只能委托设置self
的状态到不同的初始值设定项。
相反,你可以通过一点歌舞来消除可选性/失败性:
class MainViewController: NSViewController {
override init!(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// check state here and provide app-specific diagnostic if it's wrong
}
convenience override init() {
self.init(nibName: "MainView", bundle: nil)
}
// need this, too, or the compiler will complain that it's missing
required init?(coder: NSCoder) {
fatalError("not implemented") // ...or an actual implementation
}
}
An init!
初始化器生成一个隐式解包的可选(IUO)——就像 IUO 类型可用于在使用可选值和非可选值的代码之间建立桥梁一样,init!
初始化器可以在可失败初始化器和不可失败初始化器之间建立桥梁。您不能将不可失败的初始化程序委托给可失败的初始化程序,但可以将不可失败的初始化程序委托给init!
初始化器和来自init!
初始化器为可失败的初始化器。
在这里,NSViewController
你想要使用的初始化程序是完全失败的,所以你用一个覆盖它init!
初始化程序。然后,您可以声明一个不可失败的convenience init
委托给您的新init!
初始化程序。
我们常常倾向于避免 IUO,进而推而广之init!
初始化器,因为我们通常希望显式允许(并要求处理)失败或显式禁止它。然而,IUO 及其同类最强大的一般用例之一是将仅在源代码外部保证的条件转变为代码可以视为万无一失的断言。IBOutlet
就是一个很好的例子——在你的笔尖/故事板中,你可以保证你的状态IBOutlet
变量,但编译器不知道这一点——就像与捆绑资源有关的任何其他事情一样。
这个小小的委托舞蹈将失败的负担放在代码中一个特定的、易于调试的位置——如果来自init()
to super.init(nibName:bundle:)
失败,你的应用程序将会崩溃。但是您可以预期该调用仅在非常特定的(并且主要是在开发时)条件下才会失败。