__weak和__block引用之间有什么区别?


80

我正在阅读Xcode的文档,这使我感到困惑:

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

以下是从文档中复制的:

块是对其捕获的变量的有力参考。如果 self在块内使用,则该块形成对的强引用self,因此,如果 self对块也有强引用(通常这样做),则会产生强引用循环。为了避免循环,您需要__block在块外创建一个对自身的弱引用(或引用),如上例所示。

我不明白“弱(或__block)”是什么意思?

__block typeof(self) tmpSelf = self;

__weak typeof(self) tmpSelf = self;

这里完全一样吗?

我在文档中发现了另外一块:

注意:在垃圾回收的环境中,如果将__weak__block修饰符都应用于变量,则该块将无法确保其保持活动状态。

所以,我完全不解。

Answers:


109

来自有关__block的文档

__block变量位于变量的词法范围与在该变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧内声明的块的任何副本在帧的末尾都可以生存(例如,通过排队到某个地方以供以后执行),则存储将在堆栈帧的破坏中幸免。给定词法范围内的多个块可以同时使用共享变量。

来自有关__weak的文档

__weak指定一个引用,该引用不能使引用的对象保持活动状态。如果没有对对象的强引用,则将弱引用设置为nil。

因此,它们在技术上是不同的。__block用于阻止将变量从外部作用域复制到块作用域。__weak是一个自定界的弱指针。

请注意,我从技术上说过,因为对于您的情况,他们将(几乎)做同样的事情。唯一的区别是您是否使用ARC。如果您的项目使用ARC,并且仅适用于iOS4.3及更高版本,请使用__weak。如果以某种方式释放了全局范围引用,它可以确保将引用设置为nil。如果您的项目不使用ARC或用于较早的OS版本,请使用__block。

这里有一个细微的差别,请确保您理解。

编辑:另一个难题是__unsafe_unretained。该修饰符与__weak几乎相同,但用于4.3之前的运行时环境。但是,它没有设置为nil,可能会导致指针悬空。


1
这仍然适用于使用ARC的iOS7吗?我运行了探查器,即使没有在块中使用__block或__weak并引用self,我也看到控制器已被释放。
Jay Q.


1
一起使用怎么样?__block _weak NSString *strEg;
Cyber​​Mew '16

5

在手动参考计数模式下,__ block id x; 具有不保留x的效果。在ARC模式下,__ block id x; 默认保留x(就像所有其他值一样)。要获得ARC下的手动引用计数模式行为,可以使用__unsafe_unretained __block id x;。但是,正如名称__unsafe_unretained所暗示的那样,具有非保留变量是危险的(因为它可能悬挂),因此不建议使用。两种更好的选择是使用__weak(如果不需要支持iOS 4或OS X v10.6),或者将__block值设置为nil以打破保留周期。

苹果文档



0

在块中使用self时,应使用__weak而不是__block,因为它可能会保留self。

如果您需要坚强的自我,则可以这样使用:

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.