我有两个单例类。我已经在 Playground 中实现了代码。代码如下
//: Playground - noun: a place where people can play
import UIKit
class A {
private init() {
print("1")
setB()
print("2")
}
static let a = A()
func setB() {
_ = B.b
}
}
class B {
private init() {
setA()
}
static let b = B()
func setA() {
print("3")
_ = A.a // Doesn't execute beyond this
print("4")
}
}
_ = A.a
我正在外部创建 A 类
对象,后者又创建了 B 类
的对象。由于 A
是单例,因此对象已经创建。然后在 B
的构造函数中,我正在访问 A
的对象。但是代码不会超出该行执行。上面代码的输出是
1
3
任何人都可以帮我理解代码有什么问题吗?我想知道为什么它停止执行。没有语法错误/警告。
最佳答案
Since A is singleton, object is already created.
不正确。默认情况下,静态属性是惰性的。这意味着 A.a
不是B.b
将被实例化,直到它们被首次使用。这只是一个细节,因为任何初始化 A.a
的尝试将导致在初始化完成之前尝试重新访问静态属性(很可能导致线程死锁)。
当您调用 _ = A.a
时您将启动一个调用链,该链以尝试获取 A.a
的引用而结束在它完成初始化之前。
// instantiate A.a
_ = A.a
// -> calls init() of A
// -> calls setB() of A
// -> instantiates B.b
// -> calls init() of B
// -> calls setA() of B
// -> tries to grab a reference to A.a, but the
// initialization of A.a has not yet finished!
// (as you can see by the lack of printing "2").
我不完全知道这意味着什么(未定义的行为?),但可能是因为 A.a
的初始化还没完,A.a
的访问在 setA()
的 B
会相信是时候实例化A.a
了,重新启动调用链,再次尝试访问 A.a
在它被初始化之前;导致递归调用链循环(这将“卡住”并最终使 Playground 崩溃)。
正如下面我的@MartinR 所指出的,另一种可能更合理的情况是,我们实际上并没有进入递归调用链,而是进入了线程死锁(由于静态属性的线程安全性),只要我们尝试访问 A.a
在它被完全初始化之前。
无论如何,核心问题是试图访问 A.a
在它完全完成初始化之前。
关于ios - 处理多个单例类时代码卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46767434/