__block
是一个存储修饰符。它指定变量应直接被块捕获,而不是复制它。如果您需要修改原始变量,则此功能非常有用,如以下示例所示。
__block NSString *aString = @"Hey!";
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString
NSLog(@"%@", aString); // Hey!
aBlock();
NSLog(@"%@", aString); // Hello!
在ARC中,这会导致变量被自动保留,以便可以在块实现中安全地引用。在上面的例子中,当在块上下文中捕获时,
aString
将收到一个
retain
消息。
请注意,在MRC(手动引用计数)中不是这样的,在其中,变量被引用而没有被保留。
将其标记为
__weak
会导致变量不被保留,因此块直接引用它但不保留它。这可能很危险,因为如果块的生命周期比变量长,那么它将引用垃圾内存(并有可能崩溃)。
以下是
clang doc中相关的段落:
在Objective-C和Objective-C++语言中,我们允许对对象类型的__block
变量使用__weak
限定符。[...] 此限定符使这些变量保持不被发送保留消息。这会故意导致悬空指针,如果块(或副本)的生命周期超过此对象的生命周期。
最后,声称
__block
可以用来避免强引用循环(也称为保留循环)在ARC上下文中是完全错误的。由于在ARC中
__block
会导致变量被强引用,实际上更可能导致它们发生。例如,在MRC中,此代码可以打破保留循环。
__block typeof(self) blockSelf = self;
[self methodThatTakesABlock:^ {
[blockSelf doSomething];
}];
要在ARC中实现相同的结果,通常需要执行以下操作:
__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
[weakSelf doSomething];
}];
__block
有时用于避免保留循环”。 - Adam Jenkins__weak
是避免这种情况的方法。 - trojanfoe