这是来自文档,Failable Initializers for Classes部分:
class Product {
let name: String!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
if let bowTie = Product(name: "") {
// no need to check if bowTie.name == nil
print("The product's name is \(bowTie.name)")
}
这描述如下:
在上面的示例中,Product类的name属性是 定义为具有隐式展开的可选字符串类型 (串!)。因为它是可选类型,这意味着名称 property在分配特定值之前的默认值为nil 初始化期间的值。此默认值nil依次表示 Product类引入的所有属性都有 有效的初始值。因此,适用于Product的初始化程序 可以在初始化程序启动时触发初始化失败 如果在为特定值分配之前传递空字符串 初始化程序中的name属性。
看看最后一句:
因此,产品的可用初始化程序 可以在初始化程序启动时触发初始化失败 如果在为特定值分配之前传递空字符串 初始化程序中的name属性。
从提供的代码中看不到这一点。在提供的代码中,可以看出赋值发生在return nil
部分之前,并且是String(非可选)还是String? (可选)可以工作。
另一件事是,在提供的示例中,如果将其定义为常量,则使用隐式展开的可选项是没有意义的。必须在init完成之前将常量初始化为默认值。
对此有任何想法,或者是否有人看到不对此提出雷达的原因?也许我错过了什么?我有一个想法实际上为什么隐式解包可选在这里使用,但它是一个坏的例子。对我来说,这会更有意义:
class Product {
var name: String! //let is changed to var
init?(name: String) {
if name.isEmpty { return nil } //Check here if passed value is non-empty
self.name = name
}
}
这样,可以在对name
属性进行任何赋值之前触发初始化失败。
答案 0 :(得分:3)
您对误导性文档的所有疑虑都是正确的。
此外,请注意,在Swift 2.2中,早期从可用的初始化程序返回确实有效,甚至在所有属性初始化之前:
class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
另一个变化是,当从可用的初始化程序返回nil时,deinit
不再被称为。
来自Xcode 7.3 beta 2 Release Notes:
在类中,允许在初始化所有存储的属性并调用
init?()
之前退出指定的初始化程序(可以是init() throws
)或抛出(super.init()
)。支持此行为,使指定的初始化程序与便捷初始化程序更加一致。在执行self.init()
委派之前,便捷初始化程序也可能失败。