我有一些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
,并且只是永久挂起。我正在使用的示例要复杂得多,但是我相信这个小示例可以准确地再现我遇到的问题。
如何解决此问题,以便在运行代码之前等待单例设置和所有操作?
答案 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() }
}