使用__block和__weak

时间:2013-10-07 14:51:18

标签: objective-c objective-c-blocks weak-references

我已经阅读了这个帖子:What does the "__block" keyword mean?讨论了__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;

我是否需要同时使用__block__weak?这看起来有什么明显的问题吗?

2 个答案:

答案 0 :(得分: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(或副本)超过此对象的生命周期,这会故意导致悬空指针

最后,声明__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];
}];

答案 1 :(得分:14)

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

e.g:

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

如果您想避免保留周期,则应使用__weak

e.g:

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

如果有需要,您可以将它们合并。