用 strong/weak self 打破保留周期

Breaking retain cycle with strong/weak self

我读过关于 strong/weak self 打破保留周期的帖子,但我仍然对它们的工作原理感到困惑。我了解使用 __weak typeof(self) weakSelf = self 来创建对 self 的弱引用,但我对强引用感到困惑。据我了解,强引用是对 self 的强引用,这样它就不会在块结束之前被释放,对吗?那么为什么需要__strong typeof(self) strongSelf = weakSelf呢?无论如何,这最终不会指向 self 对象吗?那为什么不只是 strongSelf = self

简单来说

__weak typeof(self) weakSelf = self - 我们在块之前使用它,

这只是指向自身的指针,没有开始保留循环

-- 当且仅当块将执行时才会保留

--> 如果我们让它变强那么它就会开始保留循环并消耗内存,即使我们不调用 block

模式是:

__weak typeof(self) weakSelf = self;

[manager someAsynchronousMethodWithCompletionHandler:^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        ...
    }
}];

想法是完成处理程序块将只有对 self 的弱引用,因此如果 self 在调用完成块之前被释放,那么它将被安全地释放,因为该块没有对它的强引用。 (一个常见的例子是,当视图控制器发起一些异步网络请求来更新视图时,如果视图控制器在网络请求完成之前被关闭,那么对于一个早已消失的视图来说,挂在视图控制器实例上是没有意义的。)

但是,这个 weakSelf/strongSelf 模式还确保如果发生相反的情况,完成块已经开始并在 self 之前遇到 strongSelf 行释放后,该块将确保 self 在该块的 运行 期间保留(即它不能在完成块的 运行 中途被释放,即使如果这是 运行 在不同的线程上)。这有许多潜在的好处(从对象完整性到消除竞争条件)。有时您实际上并不需要 strongSelf 一半的“weakSelf/strongSelf 舞蹈”,但在需要时它是一个非常宝贵的工具。

但是,如果您在块中有一行内容为 typeof(self) strongSelf = self(而不是 weakSelf),则仅在该语句的右侧出现 self将导致该块预先保持对 self 的强引用,完全违背了首先使用 weakSelf 的目的。

在创建块时,您在块内引用的任何非弱对象都将导致对该对象的隐式保留。未执行,但已创建。

如果您直接从 self 初始化内部 strongSelf,您将保留 self 的值并可能导致保留循环。

另一方面,如果您从 weakSelf 初始化它,您将不会保留 weakSelf 的值。

这就是分两步的原因。外层代码将self的值复制到weakSelf中,但是ARC没有加retain,因为是__weak().

块 "creation" 复制 weakSelf 的值(或至少设法使其值在执行时可用)。你看不到它复制到哪里了,但它复制了。

在块 "execution" 时,块将 "value of weakSelf"(如果同时释放了 self,则它将为 nil)复制到 strongSelf 中,然后 ARC 对其应用保留。因此,在块的持续时间内,strongSelf 引用的对象将保持活动状态,如果它一开始是活动的。如果你只依赖 weakSelf,它可能在块执行期间随时变为 nil。

请注意 weak/strong 模式是大括号 - 许多示例实际上依赖于 weakSelf 将变为 nil 的事实,并且该块将默默地成为无操作的集合(消息为 nil ).

保留循环通常只在以下情况发生:(a) 您在 self.property 中保留对该块的引用或 (b) 您将块交给其他对象(通知管理器等),并告诉另一个对象在你的 dealloc 中忘记它;在这两种情况下,当块处于活动状态时,您的 dealloc 将永远不会被调用。

当人们说 "the way to do this stuff is with the weak/strong pattern" 时,他们是在假设最坏的情况。

有正确答案,但我真的不知道,它们是否是您问题的答案。他们解释了一般使用 self 的块的保留循环问题,但您的问题是:

So why not just strongSelf = self?

这个问题的答案:

如果有人这样做,self 将成为该块关闭的一部分并始终保留。自我弱小的整个故事就没有意义了。

必须清除一点,您没有使用 weak/strong 模式来避免保留循环!无论您是对 self 还是对 weakself 使用强引用,都不会避免保留循环。引用变量作用域打破了保留循环!当它到达作用域的末尾时,引用变量被释放。 weak/strong 模式只是一种保护机制,可以防止你对 nil 进行强引用,因为在创建块和 运行 之前,self 可能会被释放。