27

我读过这个帖子:“__block”关键字是什么意思?其中讨论了__block用途,但我对其中一个答案感到困惑。它说__block用于避免保留周期,但它下面的评论让我不确定。

我正在使用它是这样的:

 self.someProperty = x; //where x is some object (id)
 __block __weak VP_User *this = self;

 //begin a callback-style block
     this.someProperty = nil;

我需要同时使用__blockand__weak吗?这种方式看起来有什么明显的问题吗?

4

2 回答 2

60

__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++ 语言中,我们允许对象类型变量的__weak说明符。__block[...]此限定符导致保留这些变量而不发送保留消息。如果块(或副本)超过此对象的生命周期,这会故意导致悬空指针。

最后,__block可以用来避免强引用循环(也称为保留循环)的声明在 ARC 上下文中是完全错误的。由于在 ARC 中__block导致变量被强引用,它实际上更有可能导致它们。

例如,在 MRC 中,此代码打破了保留周期

__block typeof(self) blockSelf = self; //this would retain self in ARC!
[self methodThatTakesABlock:^ {
    [blockSelf doSomething];
}];

而要在 ARC 中获得相同的结果,您通常会这样做

__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
    [weakSelf doSomething];
}];
于 2013-10-07T14:59:40.080 回答
14

__block如果要更改块中的变量值,则应使用。

例如:

__block BOOL result = NO;
dispatch_sync(dispatch_get_main_queue(), ^{
  ...
  result = YES;
  ...
});

__weak如果你想避免保留循环,你应该使用。

例如:

__weak typeof(self) wself = self;
self.foobarCompletion = ^{
  ...
  wself.foo = YES;
  ...
};

如果需要,您可以将它们组合起来。

于 2013-10-07T14:59:12.930 回答