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

时间:2014-10-08 17:53:14

标签: swift initialization

以前用于Xcode 6.1 beta:

class MainViewController: NSViewController {
  convenience override init() {
    self.init(nibName: "MainView", bundle: nil)
  }
}

切换到6.1 GM2后,它无法编译。看起来这个问题与Swift 1.1中引入的“failable initializers”有关。我已经尝试convenience override init?()convenience init?()override init?(),但都没有效果。

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

1 个答案:

答案 0 :(得分: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
    }
}

init!初始值设定项生成一个隐式解包的可选项(IUO) - 正如IUO类型可用于桥接使用可选值和非可选值的代码,init!初始值设定项可以桥接在可用和不可用的初始化程序之间。您无法从不可用的初始化程序委托给可用的初始化程序,但您可以从不可用的初始化程序委托给init!初始化程序,从init!初始化程序委托给可用的初始化程序。

此处,您要使用的NSViewController初始值设定项是完全可用的,因此您可以使用init!初始化程序覆盖它。然后,您可以声明代表您的新convenience init初始值设定项的不可用init!


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

这个小团队舞会将失败的负担放在代码中特定的,易于调试的地方 - 如果从init()super.init(nibName:bundle:)的来电失败,您的应用就会崩溃。但是,您可以预期该调用仅在非常具体(并且主要是在开发时)条件下失败。