我读过一些关于使用/弱self
来打破保留循环的文章,但我仍然不太清楚它们是如何工作的。我理解使用__weak typeof(self) weakSelf = self
来创建对自身的弱引用,但我对强引用感到困惑。据我所知,强引用是为了让self
在块结束前有一个强引用,以免其被释放。那么,为什么需要__strong typeof(self) strongSelf = weakSelf
呢?这难道不会指向自身对象吗?那么为什么不直接使用strongSelf = self
呢?
我读过一些关于使用/弱self
来打破保留循环的文章,但我仍然不太清楚它们是如何工作的。我理解使用__weak typeof(self) weakSelf = self
来创建对自身的弱引用,但我对强引用感到困惑。据我所知,强引用是为了让self
在块结束前有一个强引用,以免其被释放。那么,为什么需要__strong typeof(self) strongSelf = weakSelf
呢?这难道不会指向自身对象吗?那么为什么不直接使用strongSelf = self
呢?
模式是:
__weak typeof(self) weakSelf = self;
[manager someAsynchronousMethodWithCompletionHandler:^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
...
}
}];
这个思想是完成处理程序块只会对self
进行弱引用,所以如果在完成块被调用之前释放了self
,那么它将安全地被释放,因为该块对其没有强引用。(一个常见的例子是当视图控制器启动一些异步网络请求来更新视图时,如果在网络请求完成之前关闭了视图控制器,则没必要保留已经不存在的视图控制器实例。)
但是,这种weakSelf
/strongSelf
模式还可以确保相反的情况发生,即完成块已经开始并且在self
释放之前遇到strongSelf
行,该块将确保self
在运行该块的过程中被保留(即使该块在不同的线程上运行,也不能在完成块的运行中途被释放)。这有许多潜在的好处(从对象完整性到消除竞态条件)。有时你实际上并不需要"weakSelf
/strongSelf
舞蹈"的 strongSelf 部分,但在需要时它是一个非常宝贵的工具。
然而,如果在块内部有一行代码说 typeof(self) strongSelf = self
(而不是weakSelf
),那么在该语句的右侧出现self
就会导致块在前面对self
进行强引用,完全破坏了使用weakSelf
的目的。
在块内引用的任何非弱对象都会导致对该对象进行隐式保留,因为块正在创建时发生,而不是执行时发生。
如果您直接从self初始化inner strongSelf,则会保留self的值,并可能导致保留循环。
另一方面,如果您从weakSelf初始化它,则不会保留weakSelf的值。
这就是两步的原因。外部代码将self的值复制到weakSelf中,但ARC不添加保留,因为它是__weak()。
块“创建”将weakSelf的值复制(或至少在执行时间使其值可用)。您看不到它将其复制到哪里,但确实这样做了。
在块“执行”时间,块将“weakSelf的值”(如果此时已释放self,则为nil)复制到strongSelf中,然后ARC应用保留。因此,在块的持续时间内,如果strongSelf引用的对象一开始仍然存在,则该对象将保持活动状态。如果仅依赖于weakSelf,则在块执行期间的任何时候都可能变为nil。
请注意,弱/强模式是多余的 - 许多示例实际上依赖于weakSelf将变为nil,而块将静默地成为无操作的集合(发送消息到nil)。
保留循环通常仅在(a)将块的引用保存在self.property中或(b)将块移交给其他对象(通知管理器等),并告诉该其他对象在您dealloc时忘记它时发生。在这两种情况下,只要块存在,您的dealloc就永远不会被调用。
当人们说“完成此操作的方法是使用弱/强模式”时,他们假设最坏的情况。
weakSelf = self
将weakSelf
赋值为self
的一个副本?这似乎有点奇怪,我以为它指向原始的self
。那是因为块还是变量赋值的工作方式? - somtingwongweakSelf = self
并不会将weakSelf
赋值给self
的副本。weakSelf
是指向self
的指针,当self
被释放时,该指针被设置为nil
。 - Rob有正确的答案,但我真的不知道它们是否是你问题的答案。它们通常解释了使用self的块中的保留周期问题,但你的问题是:
那为什么不只是strongSelf = self?
这个问题的答案是:
如果这样做,self
将成为块闭包的一部分,并始终被保留。弱引用就没有意义了。
简单来说
在 block 前我们使用 __weak typeof(self) weakSelf = self - 这只是指向 self 的指针,不会引起循环引用
只有当 block 执行时才会进行 retain 操作
--> 如果我们将其设为 strong,则会启动循环引用并消耗内存,即使我们不调用 block
必须要明确一点,你不是在使用弱/强引用模式来避免保留循环!无论你使用 strong 引用自己还是 weakself,都不能避免保留循环。保留循环是通过引用变量作用域来打破的!当它到达作用域的末尾时,引用变量将被解除分配。弱/强引用模式仅仅是一种保护机制,防止您引用 nil 做出强引用,因为在创建和运行块之前,self 可能已经被释放。
typeof(self) strongSelf = weakSelf;
。 - JaredHstrongSelf = weakSelf
дёҚдјҡдҪҝstrongSelf
жҢҮеҗ‘self
еҗ—пјҹжҲ–иҖ…еҸ‘з”ҹдәҶзЁҚеҫ®дёҚеҗҢзҡ„дәӢжғ…еҗ—пјҹ - somtingwongself
还没有被释放,strongSelf = weakSelf
会将strongSelf
设置为self
。但是如果在代码执行到这一行时self
已经被释放了,那么weakSelf
将会是nil
,因此strongSelf
也会被设置为nil
。 - Robself
没有被释放,那么strongSelf
将会被设置为self
,这不就等同于strongSelf = self
吗?这难道不会导致一个保留循环,使得strongSelf
永远不会随着self
一起被释放吗? - somtingwongself
,那么该块在实例化时会建立对self
的强引用(这很容易导致强引用循环)。但是,如果您引用weakSelf
,则该块的存在不会建立对self
的强引用。如果您有一行代码说strongSelf = weakSelf
,那么当块被实例化时,它不会建立强引用,而只有在运行该行代码时才会建立强引用。因此没有强引用循环。 - Rob