【问题标题】: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?如果 A 类包含对 B 类的强引用,而 B 类对 A 类有弱引用,为什么 A 总是在 B 之前得到 deinit?
【发布时间】:2021-11-14 13:24:23
【问题描述】:
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 的所有排列,但我无法在 alpha 之前让 bravo 取消初始化。根据我在 Swift Playgrounds 中的简短实验,alpha 总是在 bravo 之前得到 deinit。谁能解释一下原因?

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

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

【问题讨论】:

  • 你不能在 Playgrounds 中测试这些东西。 Playgrounds 环境有自己对对象的引用,以便显示右侧排水沟。如果您想探索它,请在命令行应用程序中探索它。

标签: swift automatic-ref-counting retaincount


【解决方案1】:

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

setup(&alpha, &bravo)

你有

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

现在您设置了bravo = nil,删除了1 个强引用,但保留了另一个强引用,因此不调用deinit,根据规则:

只要至少有一个对该实例的活动引用仍然存在,ARC 就不会释放该实例。

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

弱引用是一种不会对其引用的实例保持强控制的引用,因此不会阻止 ARC 处理引用的实例。

可以立即释放 A。同样重要的是要记住这一点

当它引用的实例被释放时,ARC 会自动设置一个对 nil 的弱引用

也就是说,操作的顺序是:

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

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

【讨论】:

  • 正是我正在寻找的答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
相关资源
最近更新 更多