两阶段初始化死锁:如果必须调用self.someMethod()来初始化类,那么如何在super.init()之前初始化类的属性?

时间:2018-08-01 11:12:41

标签: swift

与Swift的两阶段初始化相混淆。

  • 您应该在super.init()调用之前初始化所有属性
  • 要初始化它,您必须调用一些私有方法(此方法是重用目的所必需的,并且您也不想膨胀init()方法)
  • 要调用您的私有方法,您必须先调用super.init()。死锁。

这是无法编译的示例代码:

class A:NSObject {
    private var url1:URL
    private var url2:URL
    let settings:Dictionary<String, String>

    init(setting:Dictionary<String, String>) {
        self.configureAddresses()
        super.init()
    }

    private func configureAddresses() {
        /* ...some long and difficult reusable somewhere in this class configuration code... */
        self.url1 = URL(string:"result")!
        self.url2 = URL(string:"result")!
    }
}

p.s。我知道我可以在super.init()调用之前分配存根值,然后重新配置它们,但是如果我具有诸如URL或我的自定义类之类的非平凡类型的属性,那将太难看了。

2 个答案:

答案 0 :(得分:0)

选项1:

给定的代码表明URL已使用常量进行了预定义,因此请直接声明它们

class A:NSObject {
    private var url1 = URL(string:"result")!
    private var url2 = URL(string:"result")!

选项2:

文字字符串依赖于另一个值,例如在字典中,然后懒惰地声明变量并将其作为可选变量。

class A:NSObject {
       private lazy var url1 : URL? = {
           guard let result = settings["result"] as? String else { return nil }
           return URL(string: result)
       }()

在两个选项中,都交换init中的顺序

init(setting:Dictionary<String, String>) {
    super.init()
    self.configureAddresses()
}

答案 1 :(得分:0)

另一种选择,将您的configureAddresses()设为类方法:

class A: NSObject {
    private var url1: URL
    private var url2: URL
    let settings: [String: String]

    init(setting: [String: String]) {
        self.settings = setting
        (self.url1, self.url2) = A.configureAddresses()
        super.init()
    }

    private static func configureAddresses() -> (URL, URL) {
        var result1: String = ""
        var result2: String = ""
        /* ...some long and difficult reusable somewhere in this class configuration code... */
        return (URL(string: result1)!, URL(string: result2)!)
    }
}

顺便说一句,您应该更好地了解,总是避免使用Optionals远比正确使用Optionals更为糟糕