我有一些 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
,只是有点永远挂着。我正在使用的示例要复杂得多,但我相信这个小示例准确地再现了我遇到的问题。
如何解决此问题,以便在运行该代码之前等待设置单例和所有内容?
问题是你正在调用setup
,从而在init
有机会返回之前将你的refreshData
消息发送到otherManager
,所以还没有MyObject。这可以通过跳出运行循环到下一个运行循环来解决:
override init() {
super.init()
DispatchQueue.main.async { self.setup() }
}
下面是一个示例,不要调用无限共享对象,而是使用现有的单例来完成其余工作。
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)
}
}
快速的方式,如果你可以更改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
在对象有机会调用安装程序之前调用了let value: Int = test.value
的最后一行代码,这并不奇怪,因为它是async
调用。