单例初始化后立即运行代码

时间:2018-09-23 02:08:18

标签: ios swift

我有一些Swift代码,我想在单例初始化之后立即运行。初始化我的单例后,需要运行此代码的原因是因为该代码依赖于现有的单例。

我有以下目标代码示例。但是看来此代码无法正常工作,因为refreshData试图在完全创建单例之前对其进行访问。

class MyObject: NSObject {
    static let shared: MyObject = MyObject()

    let otherManager: OtherStuff = OtherStuff()

    var number: Int = 1

    override init() {
        super.init()
        setup()
    }

    func setup() {
        print("Setup code goes here")
        otherManager.refreshData()
    }
}

class OtherStuff {
    func refreshData() {
        MyObject.shared.number += 1
        print(MyObject.shared.number)
    }
}

repl.it上它会打印Setup code goes here,并且只是永久挂起。我正在使用的示例要复杂得多,但是我相信这个小示例可以准确地再现我遇到的问题。

如何解决此问题,以便在运行代码之前等待单例设置和所有操作?

3 个答案:

答案 0 :(得分:1)

在此示例中,不调用无限共享对象,而是使用现有的单例来完成其余工作。

class MyObject: NSObject {
static let shared: MyObject = MyObject()

let otherManager: OtherStuff = OtherStuff()

var number: Int = 1

override init() {
    super.init()
   setup()
}

func setup() {
    print("Setup code goes here")
    otherManager.refreshData(self)
}
}

class OtherStuff {
  func refreshData(_ myObject: MyObject) {
    myObject.number += 1
    print(myObject.number)
 }
}

答案 1 :(得分:1)

一种快速的方法,可以更改OtherManager的刷新功能签名,即将func refreshData()更改为func refreshData(for: MyObject)

static let shared: MyObject = {
    let object = MyObject()
    otherManager.refreshData(for: object)
    return object
}()

或者,尽管有点笨重(和Objective C风格),我还是要使用一个私有的shared实例,并在其属性观察器中调用setup

static var shared: MyObject {
    get {
        if _shared == nil {
            _shared = MyObject()
        }
        return _shared
    }
}

private static var _shared: MyObject! = nil {
    didSet {
        shared.setup()
    }
}

编辑:为什么DispatchQueue.main.async { self.setup() }不是正确的解决方案:

class Test: NSObject {

    var value: Int!

    override init() {
        super.init()
        DispatchQueue.main.async {
            self.setup()
        }
    }

    func setup() {
        value = 1
    }
}

let test = Test()

// error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION...
let value: Int = test.value

在对象有机会调用setup之前调用了代码let value: Int = test.value的最后一行,这并不奇怪,就像调用async一样。

答案 2 :(得分:0)

问题是您正在呼叫setup,因此在refreshData有机会返回之前,将otherManager消息发送到init,因此没有MyObject还没有。这可以通过退出运行循环到下一个运行循环来解决:

override init() {
    super.init()
    DispatchQueue.main.async { self.setup() }
}