首先,我们要知道,这些问题的答案都是我们通常应该避免依赖的实现细节。现在,回答一下:
ARC 是否保留对对象的无主引用的计数?
是的,它是真实的。每个对象都有三个引用计数:强引用计数、无主引用计数和弱引用计数。
强计数始终被存储(但存储时调整为 -1,因此存储的 0 表示强引用计数为 1,存储的 1 表示强引用计数为 2,依此类推)。
无主计数也始终被存储,调整 +1 表示所有强引用,并在去初始化结束时删除。
仅在创建对象的第一个弱引用后才存储弱引用计数。弱引用计数,如果存储的话,存储时加+1调整,它代表所有无主引用,并在对象被释放后被删除。
那么,如果一个对象的强引用计数达到 0 并且该对象的无主引用计数 > 0,则该对象将被取消初始化但不会被取消分配?
正确的。对象被取消初始化:deinit
运行对象的类和所有超类的 s,并且本身是引用的对象的任何属性都设置为 nil。但是,对象的内存不会被释放,因为对象的标头必须保持有效,直到最后一个unowned
对该对象的引用被销毁。
只有当强引用计数和无主引用计数达到 0 时,它才会被释放?
正确的。当强引用计数和无主引用计数都达到零时,该对象将被释放。由于大多数对象从未被引用过unowned
引用,这通常是在最后一个强引用被销毁时。
您没有询问弱引用,但为了完整起见,我也会解释它们。当一个对象被(或曾经被)弱引用时,Swift 会为该对象分配所谓的“侧表条目”(有时只是“侧表”)。
对对象的弱引用存储为指向边表的指针,而不是指向对象的指针。这意味着即使仍然存在对对象的弱引用,也可以释放该对象(而不仅仅是取消初始化)。
当对象被释放时,边表也被释放if没有对该对象的弱引用。如果仍然存在弱引用,则该对象将被释放,但边表仍保持分配状态。当对已释放对象的最后一个弱引用被销毁时,边表将被释放。
请注意,当 Swift 对象被取消初始化或释放时,弱引用不会立即设置为 nil(销毁)!仅当程序尝试加载引用或弱引用的容器被取消初始化时,对取消初始化对象的弱引用才会设置为 nil。 (我所说的“容器”是指,例如,当一个对象有一个weak var
财产。对象是对象的容器weak var
参考。)
顶部有一个大评论RefCount.h在 Swift 源代码中 https://github.com/apple/swift/blob/master/stdlib/public/SwiftShims/RefCount.h解释了所有这些细节以及更多。
附:还有一种参考,unowned(unsafe)
,这不会调整任何引用计数。如果可能的话,您应该避免这种引用(并且避免几乎总是可能的)。