在Swift 1.1中覆盖初始化程序的正确方法

Eth*_*han 13 initialization swift

这曾经在Xcode 6.1 beta中工作:

class MainViewController: NSViewController {
  convenience override init() {
    self.init(nibName: "MainView", bundle: nil)
  }
}
Run Code Online (Sandbox Code Playgroud)

切换到6.1 GM2后,它无法编译.看起来这个问题与Swift 1.1中引入的" failable initializers " 有关.我试过了convenience override init?(),convenience init?()而且override init?()都没有奏效.

那么今天覆盖这种初始化器的正确方法是什么?

ric*_*ter 20

您正试图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
    }
}
Run Code Online (Sandbox Code Playgroud)

一个init!初始化器产生一个隐式地展开的可选的(IUO) -只是作为一个IUO类型可以使用具有可选和非可选值工作码之间进行桥接,一个init!初始值设定failable和非failable初始化之间桥接.您不能从不可用的初始化程序委托给可用的初始化程序,但您可以从不可用的初始化程序委托给init!初始化程序,从init!初始化程序委托给可用的初始化程序.

在这里,NSViewController您要使用的初始化程序是完全可用的,因此您可以使用init!初始化程序覆盖它.然后,您可以声明一个不可用的代理convenience init到新的init!初始化程序.


我们经常倾向于避免IUO和扩展init!初始化器,因为我们通常希望明确允许(并要求处理)失败或明确禁止它.但是,IUO及其亲属最强大的一般用例之一是将仅在源代码之外保证的条件转换为您的代码可以视为绝对可靠的断言.IBOutlets就是一个很好的例子 - 在你的nib/storyboard中你可以保证IBOutlet变量的状态,但编译器并不知道 - 就像捆绑资源的任何其他事情一样.

这个小舞代表团把失败的责任在你的代码中的特定,容易调试的地方-如果从电话init()super.init(nibName:bundle:)失败,您的应用程序会崩溃.但是,您可以预期该调用仅在非常具体(并且主要是在开发时)条件下失败.

  • 疯狂.如何简洁,请苹果. (11认同)
  • 这给出了Swift 1.2的错误:"初始化程序不会覆盖其超类中指定的初始化程序"...即必须删除2. init的覆盖.即使这样,编译后第三个初始化程序抛出其致命错误.这需要如何实施? (2认同)