如果 class A 包含对 class B 的强引用,而 class B 对 class A 有弱引用,为什么 A 总是在 B 之前得到 deinit?

If class A contains a strong reference to class B and class B has a weak reference to class A, why does A always get deinit before B?

class A {
    var b: B
    
    init(b: B) {
        self.b = b
    }
    
    deinit {
        print("  Destroying A")
    }
}

class B {
    weak var a: A?
    
    deinit {
        print("  Destroying B")
    }
}

func setup(_ a: inout A?, _ b: inout B?) {
    b = B()
    a = A(b: b!)
    b?.a = a
}

var bravo: B?
var alpha: A?
setup(&alpha, &bravo)

bravo = nil
alpha = nil

// OUTPUT:
// "  Destroying A"
// "  Destroying B"

我已经尝试了将 alphabravo 设置为 nil 的所有排列,但我无法让 bravoalpha 之前取消初始化。根据我在 Swift Playgrounds 中的简短实验,alpha 总是在 bravo 之前获得 deinit。有人可以解释一下为什么吗?

我知道这与ARC有关,但我想如果bravo = nil,那么alpha.b的值不也是nil吗?如果是这样,那么在 alpha 之前安全地 deinit bravo 不是安全的吗?

我很想知道随着时间的推移,每个实例的保留计数是多少。

不确定我是否理解了这个问题,但我认为这是 ARC rules 的非常直接的应用。行后

setup(&alpha, &bravo)

你有

  • 2 对对象 bravo 的强引用(bravo 本身及其引用 alpha.b
  • 1 个强引用(alpha 本身)和 1 个弱引用(bravo.a)对象 alpha

现在你设置了bravo = nil,删除了1个强引用,但是另一个强引用仍然存在,所以deinit没有被调用,基于规则:

ARC will not deallocate an instance as long as at least one active reference to that instance still exists.

接下来设置 alpha = nil。那是删除它唯一的强引用,因此基于规则

A weak reference is a reference that doesn’t keep a strong hold on the instance it refers to, and so doesn’t stop ARC from disposing of the referenced instance.

A 可以立即解除分配。同样重要的是要记住

ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated

也就是说,运算顺序是:

  1. 使用 alpha = nil
  2. 删除字符串引用
  3. 由于没有其他强引用,所有弱引用都设置为nil
  4. deinit被称为

所以现在 alpha 被删除了,bravo 没有留下任何类型的引用,因此它的 deinit 可以被调用。