Swift 即使 self 保持存在,弱引用也会变为 nil

Swift weak reference going nil even when self keeps existing

我想弄清楚为什么即使对象保持存在,弱引用也会丢失其引用的对象。

我的代码如下:

MyClass {
    deinit {
        print("I'm being deinited") // This never gets called
    }
    func doConnection(connection: Future<Data, ServerConnectionError>) {
        Future<Void, ServerConnectionError> { complete in
            connection.onSuccess {[weak self] data in
                guard let strongSelf = self else {
                    return // This line gets called
                }
                ...
            }
        }
    }
}

通过检查内存图,我可以看到在 future 完成之前由 self 引用的对象仍然存在(根据内存地址判断)。

在发现其弱引用为 nil(最右边的 MyClass 实例)后,假定丢失的对象的内存图如下所示:

上面的子树应该保持对象存活,而底部的子树与当前堆栈执行有关。在第 3 级(从右到左)中被许多其他对象引用的对象(蓝色框)持有对数组的强引用,而数组又持有对 MyClass 实例的引用。

编辑:问题已在下面的答案中解决。冷却时间结束后将标记为已解决。

将包含 self 的任何捕获列表移动到最外层的闭包,否则它可能会创建引用循环:

MyClass {
    deinit {
        print("I'm being deinited") // This never gets called
    }
    doConnection(connection: Future<Data, ServerConnectionError>) { [weak self] in
        Future<Void, ServerConnectionError> { complete in
            connection.onSuccess { data in
                guard let strongSelf = self else {
                    return // This line gets called
                }
                ...
            }
        }
    }
}

默认情况下,闭包表达式通过对这些值的强引用从其周围范围捕获属性。但是你在 closure/promise 中将自己定义为弱者。您可以删除 [weak self] 使用 [unowned self] 或将闭包列表移至外部块。只要您的 MyClass 实例在履行诺言时未被释放。只有当内存压力触发垃圾收集时,才会释放没有强引用的对象。但是,在 ARC 中,一旦 最后一个强引用被移除,值就会被释放。通过在闭包中设置 self weak,您允许 ARC 在没有其他强引用存在时删除对 MyClass 实例的引用,您的弱引用将在 MyClass 实例被取消初始化后删除。

问题已解决。好的,所以我不知道发生了什么,但在多次尝试调试后它自行修复。仍然有问题的一件事是调试器在闭包内将 self 显示为 nil(这在调试过程中增加了重要的时间),但是 guard let 块成功执行并且我得到对该对象的强引用。