80

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

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

以下是从文档中复制的:

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

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

__block typeof(self) tmpSelf = self;

__weak typeof(self) tmpSelf = self;

这里一模一样?</p>

我在文档中找到了另一篇文章:

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

所以,我完全感到困惑。

4

4 回答 4

109

来自关于 __block 的文档

__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧中声明的块的任何副本在帧结束后仍然存在(例如,通过在某处排队以供稍后执行),则存储将在堆栈帧的破坏中幸存下来。给定词法范围内的多个块可以同时使用一个共享变量。

来自关于 __weak 的文档

__weak 指定一个不使被引用对象保持活动状态的引用。当对象没有强引用时,弱引用设置为 nil。

所以它们在技术上是不同的东西。__block 是为了阻止你的变量从你的外部作用域复制到你的块作用域。__weak 是一个自定界的弱指针。

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

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

编辑:另一个难题是__unsafe_unretained。此修饰符与 __weak 几乎相同,但适用于 4.3 之前的运行时环境。但是,它没有设置为 nil,并且可能会给您留下悬垂的指针。

于 2012-08-02T08:19:24.757 回答
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 以中断保留周期。

苹果文档

于 2013-07-31T08:32:48.213 回答
0

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

如果你需要强大的自我,那么你可以这样使用:

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
于 2019-05-01T22:44:29.663 回答
0

除了__blockvs的其他答案之外__weak,还有另一种方法可以避免您的场景中的保留周期。

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

关于@Weakify @Strongify 宏的更多信息

于 2018-01-26T08:58:22.800 回答