“__block”是什么意思?
Objective-C中的__block
关键字是什么意思? 我知道它允许你修改块内的variables,但我想知道…
- 究竟是什么告诉编译器?
- 它做了什么吗?
- 如果是这样,那么为什么它需要摆在首位呢?
- 它在任何地方的文档? (我找不到)。
它告诉编译器,任何由它标记的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
块之前, localCounter
和localCharacter
都被修改。 但是,在块内部,只有对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是一个可用于两种方式的存储限定符:
-
标记variables存在于原始variables的词法范围和在该范围内声明的任何块之间共享的存储中。 而铿锵会生成一个结构来表示这个variables,并通过引用(而不是值)使用此结构。
-
在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;