在Swift中实现Failable Initializer时,为什么要使用`init!`而不是`init?`?

时间:2015-07-23 21:33:17

标签: swift initialization optional

Swift文档Initialization: Failable Initializers详细说明了如何使用init?创建一个可用的初始化程序,它是一个初始化程序,它返回它初始化类型的可选。与所有可选项一样,它可以是nil或非nil

文档还提到您可以使用init!创建一个可用的初始值设定项,它返回一个隐式解包的可选它初始化的类型(参见 init!Failable Initializer 部分)。这将打开可选项并指示它"应该"不是nil。如果它是nil并且您在没有检查的情况下访问它,那么程序员可能会跳过它,因为它被标记为"应该是非nil",将生成运行时错误。

两个问题:

  1. 在实施可用的初始值设定项时,/为什么要使用init!而不是init?
  2. 由于init!总是返回一个隐式解包的可选项,其中"应该"不是nil,为什么你不能使用init代替init!

3 个答案:

答案 0 :(得分:6)

在绝大多数情况下,您应该使用init!而不是init!。在某些情况下struct NotEmpty { let something: String init?(something: String) { guard !something.isEmpty else { return nil } self.something = something } init() { self.init(something: "unknown")! // <-- This is illegal } } 是必要的。在我的经历中最常见的是当一个&#34;必须成功&#34;初始化程序想要调用一个可用的初始化程序。考虑这种情况:

init()

我们知道init!会成功,因为我们传递的是非空字符串。但是没有办法用标准的初始化程序表达它(并且编译器无论如何也无法证明它是真的)。相反,我们需要使用init!() { self.init(something: "unknown") }

!

现在调用者可以将结果视为非可选(实际上是非),即使根据它可能失败的类型也是如此。这将是一个编程错误,你崩溃了。 $(gridHeader).find("tr:gt(0)").hide(); 在这里基本上说'#34;是的,我知道它可能会失败,但我保证它永远不会。&#34;在斯威夫特,&#34;承诺&#34;意味着&#34;否则请崩溃。&#34;

答案 1 :(得分:1)

您可以从init委派吗?初始化!反之亦然,你可以覆盖init吗?用init!反之亦然。

这意味着如果您确定它不会失败,您可以将某些init?转换为init!,反之亦然。在文档中有以下示例:

enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
        init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}

你可以有一些类似的代码,你可以只使用常量初始化它,而不是使用用户输入或其他一些输入源。所以你很确定它不会失败,为什么不把它变成init!

答案 2 :(得分:0)

您可以在类中使用它来覆盖可用的初始化程序并使其不可用。

在处理隐式展开时必须同样谨慎:它可能很危险,因为它有能力使应用程序崩溃。