一尘不染

在Swift中实现可失败的初始化程序的最佳实践

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()
    }
}

阅读 338

收藏
2020-07-07

共1个答案

一尘不染

更新:Swift
2.2更改日志
(2016年3月21日发布):

现在,在对象已完全初始化之前,声明为失败或抛出的指定类初始化器可能分别返回nil或抛出错误。


对于Swift 2.1和更早版本:

根据Apple的文档(以及您的编译器错误),类必须nil从失败的初始化程序返回之前,初始化其所有存储的属性:

但是,对于类而言,只有在该类引入的所有存储属性都已设置为初始值并且已执行任何初始化程序委托之后,可故障初始化程序才能触发初始化失败。

注意: 它实际上适用于结构和枚举,但不适用于类。

处理在初始化程序失败之前无法初始化的存储属性的建议方法是,将它们声明为隐式展开的可选属性。

来自文档的示例:

class Product {
    let name: String!
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

在上面的示例中,Product类的name属性定义为具有隐式展开的可选字符串类型(String!)。因为它是可选类型,所以这意味着name属性在初始化期间被分配特定值之前具有默认值nil。该默认值nil依次意味着Product类引入的所有属性都具有有效的初始值。结果,如果为Product设置了失败的初始化程序,则在为初始化程序内的name属性分配特定值之前,如果将其传递给空字符串,则会在初始化程序启动时触发初始化失败。

但是,在您的情况下,仅定义userName为a
String!并不能解决编译错误,因为您仍然需要担心在基类上初始化属性NSObject。幸运的是,使用userName定义为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
    }
}
2020-07-07