Kai*_*ann 98 object-initializers swift
使用以下代码,我尝试定义一个简单的模型类,它是可用的初始化器,它将(json-)字典作为参数.nil如果未在原始json中定义用户名,则应返回初始化程序.
1.为什么代码不能编译?错误消息说:
在从初始化程序返回nil之前,必须初始化类实例的所有存储属性.
这没有意义.我计划返回时为什么要初始化这些属性nil?
2.我的方法是正确的,还是会有其他想法或共同模式来实现我的目标?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
Run Code Online (Sandbox Code Playgroud)
mus*_*afa 131
这没有意义.当我计划返回nil时,为什么要初始化这些属性?
根据Chris Lattner的说法,这是一个错误.他说的是这样的:
这是swift 1.1编译器中的实现限制,在发行说明中有记录.编译器目前无法在所有情况下销毁部分初始化的类,因此它不允许形成必须的情况.我们认为这是一个在将来的版本中修复的错误,而不是一个功能.
编辑:
所以swift现在是开源的,根据这个更改日志,现在修复了swift 2.2的快照
声明为failable或throw的指定类初始值设定项现在可以在对象完全初始化之前分别返回nil或抛出错误.
Mik*_*e S 69
更新:来自Swift 2.2更改日志(2016年3月21日发布):
声明为failable或throw的指定类初始值设定项现在可以在对象完全初始化之前分别返回nil或抛出错误.
对于Swift 2.1及更早版本:
根据Apple的文档(以及您的编译器错误),类必须在nil从可用的初始化程序返回之前初始化其所有存储的属性:
但是,对于类,只有在该类引入的所有存储属性都已设置为初始值并且已执行任何初始化程序委派之后,可用的初始化程序才会触发初始化失败.
注意:它实际上适用于结构和枚举,而不是类.
处理在初始化程序失败之前无法初始化的存储属性的建议方法是将它们声明为隐式解包的选项.
来自文档的示例:
class Product {
let name: String!
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,Product类的name属性被定义为具有隐式解包的可选字符串类型(String!).因为它是可选类型,这意味着在初始化期间为name属性分配特定值之前,name属性的默认值为nil.此默认值nil反过来意味着Product类引入的所有属性都具有有效的初始值.因此,如果在初始化程序中为name属性指定特定值之前传递空字符串,那么Product的初始化程序可以在初始化程序启动时触发初始化失败.
但是,在您的情况下,简单地定义userName为String!不会修复编译错误,因为您仍然需要担心初始化基类的属性,NSObject.幸运的是,userName定义为a String!,你可以super.init()在你之前调用return nil它来初始化你的NSObject基类并修复编译错误.
class User: NSObject {
let userName: String!
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
super.init()
if let value = dictionary["user_name"] as? String {
self.userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
self.isSuperUser = value
}
self.someDetails = dictionary["some_details"] as? Array
}
}
Run Code Online (Sandbox Code Playgroud)
我接受Mike S的回答是Apple的建议,但我不认为这是最好的做法.强类型系统的重点是将运行时错误移动到编译时.这种"解决方案"违背了这一目的.恕我直言,更好的是继续初始化用户名"",然后在super.init()之后检查它.如果允许空白用户名,则设置标志.
class User: NSObject {
let userName: String = ""
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: [String: AnyObject]) {
if let user_name = dictionary["user_name"] as? String {
userName = user_name
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
if userName.isEmpty {
return nil
}
}
}
Run Code Online (Sandbox Code Playgroud)
避免限制的另一种方法是使用类函数来进行初始化.您甚至可能希望将该功能移动到扩展名:
class User: NSObject {
let username: String
let isSuperUser: Bool
let someDetails: [String]?
init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
self.userName = userName
self.isSuperUser = isSuperUser
self.someDetails = someDetails
super.init()
}
}
extension User {
class func fromDictionary(dictionary: NSDictionary) -> User? {
if let username: String = dictionary["user_name"] as? String {
let isSuperUser = (dictionary["super_user"] as? Bool) ?? false
let someDetails = dictionary["some_details"] as? [String]
return User(username: username, isSuperUser: isSuperUser, someDetails: someDetails)
}
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
使用它将成为:
if let user = User.fromDictionary(someDict) {
// Party hard
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19561 次 |
| 最近记录: |