使用__block和__weak

Ada*_*dam 27 weak-references objective-c objective-c-blocks

我已经读完了这个帖子:"__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;
Run Code Online (Sandbox Code Playgroud)

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

Gab*_*lla 60

__block是存储限定符.它指定该块应该直接捕获该变量,而不是复制它.这在您需要修改原始变量时很有用,如下例所示

__block NSString *aString = @"Hey!"; 
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString
NSLog(@"%@", aString); // Hey!
aBlock();
NSLog(@"%@", aString); // Hello!
Run Code Online (Sandbox Code Playgroud)

在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];
}];
Run Code Online (Sandbox Code Playgroud)

而在ARC中实现相同的结果,通常是这样做的

__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
    [weakSelf doSomething];
}];
Run Code Online (Sandbox Code Playgroud)

  • 不.如果您想修改块中的对象,可能有意义,但保持对它的引用会导致保留周期.我无法想出一个好的例子,但可能存在合法用途.这就是为什么它被允许,即使可能不安全,正如文档评论. (3认同)
  • 如果我没有错,那么为了保留周期,你必须在`self`中保持对该块的直接或间接引用(例如`self.block = block`).因此,仅使用块内的"self"不会创建保留周期.如果不存储块,则不需要`weakSelf`. (2认同)

Ale*_*kov 14

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

例如:

__block BOOL result = NO;
dispatch_sync(dispatch_get_main_queue(), ^{
  ...
  result = YES;
  ...
});
Run Code Online (Sandbox Code Playgroud)

__weak如果要避免保留周期,则应使用.

例如:

__weak typeof(self) wself = self;
self.foobarCompletion = ^{
  ...
  wself.foo = YES;
  ...
};
Run Code Online (Sandbox Code Playgroud)

如果有需要,您可以将它们组合在一起.