ios - 处理多个单例类时代码卡住

标签 ios swift swift3

我有两个单例类。我已经在 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/

相关文章:

ios - 更改单元格高度后 UITableView 在滚动时跳动

ios - 如何创建带有图标下标题和外框的按钮

ios - 无法将图像加载到 ScrollView 中进行缩放和滚动

swift - 获取 Swift 4 中 UITextField 的字段名称

ios - 如何跟踪 UICollectionView 索引

ios - 从 Swift IOS 套接字获取 InputStream 中的文件

ios - AnyObject 到 swift 字符串

ios - UICollectionViewCell 的动态高度

ios - 更改 Collection View 单元格大小

arrays - 如何在 Swift 中访问 `AnyHashable` 中的 `Any` 类型?