返回

GCD 捕获 self:揭开循环引用的谜团

IOS

GCD 的世界

GCD(Grand Central Dispatch)是 Apple 提供的一套强大且易于使用的并发编程框架。它允许开发者在并发队列上执行任务,从而充分利用多核处理器的优势。

GCD 块是一种匿名函数,用于指定在队列上执行的任务。它可以捕获外部变量,包括 self,这是指向当前对象的指针。

循环引用的争论

当一个对象引用另一个对象时,就会产生循环引用。当这些对象都强引用对方时,就会形成一个循环,导致无法释放内存。

当 GCD 块捕获 self 时,就可能产生循环引用。这是因为 self 强引用 GCD 块,而 GCD 块又强引用 self

然而,对于 GCD 捕获 self 是否会导致循环引用,一直存在着争论。一些开发者认为会,而另一些开发者则认为不会。

YYKit 的启示

YYKit 是一个流行的 iOS 开源库,提供了一系列有用的实用程序。它在处理 GCD 块和 self 时遵循以下规则:

  1. 对于在主队列上执行的块,不要捕获 self
  2. 对于在并发队列上执行的块,如果捕获了 self,则必须在块中对 self 进行弱引用。

深入分析

为了理解 YYKit 规则背后的原因,我们需要更深入地了解 GCD 的内存管理。

当一个 GCD 块在主队列上执行时,它与主线程的运行循环相关联。主线程有一个强引用计数,只要它正在运行,它就永远不会被释放。因此,即使 GCD 块捕获了 self,它也不会造成循环引用,因为主线程始终保持对 self 的强引用。

但是,当一个 GCD 块在并发队列上执行时,它与主线程的运行循环无关。并发队列没有强引用计数,因此它们可以随时释放。如果 GCD 块捕获了 self,并且对 self 的引用是强的,那么当并发队列释放时,self 也将被释放。这将导致循环引用,因为 GCD 块仍然强引用 self,而 self 已经被释放。

解决循环引用

为了避免循环引用,在并发队列上执行的 GCD 块中捕获 self 时,必须对 self 进行弱引用。弱引用是一种特殊的引用,不会阻止对象被释放。

在 Swift 中,可以使用以下语法创建弱引用:

weak var weakSelf = self

然后,在 GCD 块中,可以使用 weakSelf 代替 self。这样,当并发队列释放时,weakSelf 将被自动置为 nil,从而打破循环引用。

结论

GCD 捕获 self 是否会导致循环引用,取决于 GCD 块是在主队列还是并发队列上执行的。在主队列上执行时不会造成循环引用,而在并发队列上执行时则必须对 self 进行弱引用。

YYKit 遵循这些规则以确保安全使用 GCD。通过理解这些规则并正确使用弱引用,开发者可以避免内存泄漏并编写高效、健壮的代码。