Swift文档Initialization: Failable Initializers详细说明了如何使用init?
创建一个可用的初始化程序,它是一个初始化程序,它返回它初始化类型的可选。与所有可选项一样,它可以是nil
或非nil
。
文档还提到您可以使用init!
创建一个可用的初始值设定项,它返回一个隐式解包的可选它初始化的类型(参见 init!Failable Initializer 部分)。这将打开可选项并指示它"应该"不是nil
。如果它是nil
并且您在没有检查的情况下访问它,那么程序员可能会跳过它,因为它被标记为"应该是非nil
",将生成运行时错误。
两个问题:
init!
而不是init?
?init!
总是返回一个隐式解包的可选项,其中"应该"不是nil
,为什么你不能使用init
代替init!
?答案 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)
您可以在类中使用它来覆盖可用的初始化程序并使其不可用。
在处理隐式展开时必须同样谨慎:它可能很危险,因为它有能力使应用程序崩溃。