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

它到底告诉编译器什么? 它还有别的功能吗? 如果这就是它所做的一切,那么为什么首先需要它呢? 文档里有吗?(我找不到)。


@bbum在一篇博客文章中深入介绍了块,并涉及到__block存储类型。

__block是一种独特的存储类型 就像static、auto和volatile一样,__block也是一种存储类型。它 告诉编译器要管理变量的存储 不同的… 然而,对于__block变量,块不保留。根据需要,您可以保留或释放它。 ...

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

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

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

有关示例和更多信息,请参见Apple的块编程主题中的__block存储类型。

一个重要的例子是:

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和localCharacter都被修改了。然而,在块内部,由于__block关键字,只有对localCharacter的修改是可见的。相反,块可以修改localCharacter,并且这种修改在块外部是可见的。


来自块语言规范:

In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are. In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.

有关__block变量应该编译为什么的详细信息,请参见块实现规范,第2.3节。


__block是一种存储类型,用于使作用域变量可变,更坦率地说,如果你声明一个变量与此说明符,它的引用将被传递给块而不是只读副本,详情请参阅iOS中的块编程


希望这对你有所帮助

让我们假设我们有这样一个代码:

{
     int stackVariable = 1;

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

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

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


__block是一个存储限定符,可以以两种方式使用:

标记变量位于原始变量的词法作用域和在该作用域中声明的任何块之间共享的存储中。clang将生成一个表示该变量的结构体,并通过引用(而不是值)使用该结构体。 在MRC中,__block可用于避免保留块捕获的对象变量。注意这对ARC不起作用。在ARC中,你应该使用__weak。

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


当你不使用__block时,块会复制变量(按值调用),所以即使你在其他地方修改了变量,块也看不到变化。

__block使块保持对变量的引用(引用调用)。

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

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

If you want to modify the variable inside the block and expect it to be visible outside: __block NSString* str = @"hello"; void (^theBlock)() = ^void() { str = @"how are you"; }; theBlock(); NSLog(@"%@", str); //prints "how are you" If you want to modify the variable after you have declared the block and you expect the block to see the change: __block NSString* str = @"hello"; void (^theBlock)() = ^void() { NSLog(@"%@", str); }; str = @"how are you"; theBlock(); //prints "how are you"


这意味着它作为前缀的变量可以在块中使用。