我正在尝试以下闭包保留周期的实验:
输出结果将会是:
这次输出结果为:
class Sample {
deinit {
print("Destroying Sample")
}
func additionOf(a: Int, b:Int) {
print("Addition is \(a + b)")
}
func closure() {
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
self?.additionOf(3, b: 3)
usleep(500)
self?.additionOf(3, b: 5)
}
}
}
稍后的某个时间点,我正在进行
var sample : Sample? = Sample()
sample?.closure()
dispatch_async(dispatch_get_global_queue(0, 0)) {
usleep(100)
sample = nil
}
输出结果将会是:
Addition is 6
Destroying Sample
这是可以理解的,因为在执行 self?.additionOf(3, b:5)
之前,self
已经被设为了 nil。
如果我在闭包内创建另一个变量引用 [weak self]
,像下面这样做出改变:
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.additionOf(3, b: 3)
usleep(500)
strongSelf.additionOf(3, b: 5)
}
这次输出结果为:
Addition is 6
Addition is 8
Destroying C
我的问题是为什么在sample = nil
之后,strongSelf
没有被置为nil。这是因为它在闭包内被捕获之前就已经被捕获了吗。
sample = nil
时,你所做的仅仅是解决对Sample
的那一个强引用。但它对于可能存在的其他强引用没有任何影响(比如在你执行sample = nil
之前分配的strongSelf
)。在[weak self]
闭包内部进行strongSelf
模式的整个目的(有时开玩笑地称为“strongSelf/weakSelf dance”)是确保如果在该闭包开始时Sample
未被释放,则将其保留直至该闭包完成。 - RobadditionOf(3, b: 3)
之前,Sample还没有被释放。我仍然不明白为什么strongSelf
没有改变,因为self已经被nil化了。除非它被捕获在闭包内? - tonytranSample
对象。所以,当你调用var sample: Sample? = Sample()
时,有一个强引用。当代码遇到guard let strongSelf = self else ...
时,这建立了第二个强引用,总共有两个强引用。当你在主线程上执行sample = nil
时,仍然有一个强引用。只有当strongSelf
超出范围时,才会解决这个最终的强引用,并且对象被释放。 - Rob