__weak和__block引用有什么区别?

问题描述 投票:76回答:4

我正在阅读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修饰符同时应用于变量,则该块将无法确保它保持活动状态。

所以,我完全不解。

objective-c memory-management objective-c-blocks weak-references ownership
4个回答
105
投票

来自关于__block的文档

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

来自关于__weak的文档

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

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

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

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

编辑:拼图的另一个部分是__unsafe_unretained。此修饰符与__weak几乎相同,但适用于4.3之前的运行时环境。但是,它没有设置为nil,可以给你留下指针。


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以打破保留周期。

apple docs


0
投票

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

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

More Info about @Weakify @Strongify Macro


0
投票

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

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

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
© www.soinside.com 2019 - 2024. All rights reserved.