ChatGPT解决这个技术问题 Extra ChatGPT

__weak 和 __block 引用有什么区别?

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

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

以下是从文档中复制的:

块形成对其捕获的变量的强引用。如果你在一个块中使用 self ,这个块形成一个对 self 的强引用,所以如果 self 也有一个对块的强引用(它通常这样做),就会产生一个强引用循环。为避免循环,您需要在块外创建对 self 的弱(或 __block)引用,如上例所示。

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

__block typeof(self) tmpSelf = self;

__weak typeof(self) tmpSelf = self;

这里一模一样?

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

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

所以,我完全感到困惑。


P
Paul de Lange

来自关于 __block 的文档

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

来自关于 __weak 的文档

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

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

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

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

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


这仍然适用于使用 ARC 的 iOS7 吗?我运行了一个分析器,我看到我的控制器正在被释放,即使我不使用 __block 或 __weak 并在一个块中引用 self 。
一起使用怎么样? __block _weak NSString *strEg;
M
Marc Liyanage

在手动引用计数模式下,__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 以中断保留周期。

apple docs


C
Cœur

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

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

More Info about @Weakify @Strongify Macro


d
david72

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

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

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];