“__block”是什么意思?

Objective-C中的__block关键字是什么意思? 我知道它允许你修改块内的variables,但我想知道…

  1. 究竟是什么告诉编译器?
  2. 它做了什么吗?
  3. 如果是这样,那么为什么它需要摆在首位呢?
  4. 它在任何地方的文档? (我找不到)。

它告诉编译器,任何由它标记的variables在块内使用时都必须以特殊方式处理。 通常情况下,复制在块中使用的variables及其内容,因此对这些variables所做的任何修改都不会显示在块之外。 当它们用__block标记时,在块内完成的修改在其外部也是可见的。

有关示例和更多信息,请参阅Apple的Blocks编程主题中 的__block存储types 。

重要的例子是这一个:

 extern NSInteger CounterGlobal; static NSInteger CounterStatic; { NSInteger localCounter = 42; __block char localCharacter; void (^aBlock)(void) = ^(void) { ++CounterGlobal; ++CounterStatic; CounterGlobal = localCounter; // localCounter fixed at block creation localCharacter = 'a'; // sets localCharacter in enclosing scope }; ++localCounter; // unseen by the block localCharacter = 'b'; aBlock(); // execute the block // localCharacter now 'a' } 

在这个例子中,在localCounter块之前, localCounterlocalCharacter都被修改。 但是,在块内部,只有对localCharacter的修改才可见,这要归功于__block关键字。 相反,块可以修改localCharacter ,这个修改在块的外面是可见的。

@bbum覆盖博客文章中的深度块,并触及__block存储types。

__block是一个独特的存储types

就像静态,自动和易失性一样,__block是一种存储types。 它告诉编译器,variables的存储是以不同的方式pipe理的。

但是,对于__blockvariables,块不保留。 根据需要,由您来保留和发布。

至于用例,你会发现__block有时被用来避免保留周期,因为它不保留参数。 一个常见的例子是使用自我。

 //Now using myself inside a block will not //retain the value therefore breaking a //possible retain cycle. __block id myself = self; 

__block是一个可用于两种方式的存储限定符:

  1. 标记variables存在于原始variables的词法范围和在该范围内声明的任何块之间共享的存储中。 而铿锵会生成一个结构来表示这个variables,并通过引用(而不是值)使用此结构。

  2. 在MRC中,可以使用__block来避免块捕获的保留对象variables。 小心这不适用于ARC。 在ARC中,您应该使用__weak

你可以参考苹果文档的详细信息。

__block是一个存储types,用于使范围variables可变,更坦率地说,如果你用这个说明符声明了一个variables,它的引用将被传递给块而不是只读副本,更多细节请参阅块编程在iOS

通常当你不使用__block时,块将复制(保留)variables,所以即使你修改了variables,块也可以访问旧的对象。

 NSString* str = @"hello"; void (^theBlock)() = ^void() { NSLog(@"%@", str); }; str = @"how are you"; theBlock(); //prints @"hello" 

在这两种情况下,你需要__block:

1.如果要修改块内部的variables,并期望它在外面可见:

 __block NSString* str = @"hello"; void (^theBlock)() = ^void() { str = @"how are you"; }; theBlock(); NSLog(@"%@", str); //prints "how are you" 

2.如果要在声明块之后修改variables,并希望块能看到更改:

 __block NSString* str = @"hello"; void (^theBlock)() = ^void() { NSLog(@"%@", str); }; str = @"how are you"; theBlock(); //prints "how are you" 

来自块语言规范 :

除了新的Blocktypes外,我们还为本地variables引入了一个新的存储限定符__block。 [testme:块内容中的__block声明] __block存储限定符与现有本地存储限定符auto,register和static是互斥的[testme] __block限定的variables的行为就好像它们在分配的存储中一样,在最后使用所述variables后自动恢复。 一个实现可以select一个优化,其中存储是初始自动的,并且在引用块的Block_copy上仅被“移动”到分配(堆)存储。 这些variables可能会像正常variables一样发生变异。

在__blockvariables是块的情况下,必须假定__blockvariables驻留在分配的存储器中,并且因此被假定引用也在分配的存储器中的块(即Block_copy操作的结果)。 尽pipe如此,如果一个实现为块提供了初始自动存储,则不需要做Block_copy或Block_release。 这是由于潜在的几个线程尝试更新共享variables的固有争用条件,以及需要同时处理旧值和复制新值。 这种同步超出了这个语言规范的范围。

有关__blockvariables应该编译到的细节,请参见块实现规范 ,第2.3节。

希望这会帮助你

假设我们有这样的代码:

 { int stackVariable = 1; blockName = ^() { stackVariable++; } } 

它会给出一个错误,如“variables不可赋值”,因为块内的栈variables默认是不可变的。

在它声明之前加上__block(存储修饰符)使它在块内是可变的,即__block int stackVariable=1;