Swift弱引用即使self仍然存在也会变为nil

4
我正在尝试弄清楚为什么即使对象一直存在,弱引用仍会失去其所引用的对象。
我的代码如下:
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
                }
                ...
            }
        }
    }
}

通过检查内存图,我可以看到在未来完成之前被self引用的对象仍然存在(根据内存地址判断)。
在找到弱引用为nil后,所谓缺失对象的内存图如下(最右侧为MyClass实例):

Memory graph showing two main references to the object

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

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

3个回答

2

问题已解决。好的,我不知道发生了什么事情,但在多次尝试调试后,它自己修复了。仍然存在一个错误,即调试器在闭包内显示selfnil(这在调试过程中花费了很长时间),但是guard let块成功执行并且我得到了对该对象的强引用。


0

将包含 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
                }
                ...
            }
        }
    }
}

由于这是一个类方法(抱歉,忘记添加 func),我无法在那里放置捕获列表。我已经尝试将捕获列表放置在 Future<Void... 行中,但没有成功。 - Gonzalo
当您移除此代码行时,它会每次反初始化吗?我们确定这是罪魁祸首? - trndjc
请看我的回答。我想这可能是编译器的问题,因为尝试了几次后它自己修复了。此外,调试器显示的信息是错误的。 - Gonzalo

0
默认情况下,闭包表达式会使用对其周围作用域中的属性进行强引用。但是在你的闭包/承诺中,你将self定义为weak。你可以删除[weak self]并使用[unowned self]或将闭包列表移动到外部块中。只要MyClass实例在承诺被实现时没有被解除分配。没有强引用的对象仅在内存压力触发垃圾回收时才被解除分配。然而,在ARC中,只要最后一个强引用被移除,值就会立即被解除分配。通过在闭包中使self变为weak,当没有其他强引用存在时,你允许ARC删除对MyClass实例的引用,你的弱引用将在MyClass实例被析构后被删除。

我知道weak表示该对象可以被释放,而我也可以接受这一点。如果引用丢失,我不想执行与之相关的代码。问题在于该对象仍然存在于内存中,并且始终被强引用。它的deinit方法从未被调用,因此它永远不会失去所有强引用。 - Gonzalo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接