关于C#:”__block”关键字是什么意思?

What does the “__block” keyword mean?

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

  • 它到底告诉编译器什么?
  • 它还能做什么吗?
  • 如果这就是全部,那么为什么首先需要它呢?
  • 文件里有吗?(我找不到)。

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

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

    重要的例子是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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'
    }

    在本例中,在调用块之前修改localCounterlocalCharacter。但是,在该块中,只有对localCharacter的修改才可见,这要归功于__block关键字。相反,该块可以修改localCharacter,并且该修改在块外部可见。


    @bbum在博客文章中深入介绍了block,并介绍了uu block存储类型。

    __block is a distinct storage type

    Just like static, auto, and volatile, __block is a storage type. It
    tells the compiler that the variable’s storage is to be managed
    differently.

    ...

    However, for __block variables, the block does not retain. It is up to you to retain and release, as needed.

    ...

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

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


    _块是一个存储限定符,可以通过两种方式使用:

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

  • 在MRC中,可以使用_uu块来避免保留块捕获的对象变量。小心这对ARC不起作用。在ARC中,您应该使用"弱"。

  • 有关详细信息,请参阅Apple Doc。


    通常,当不使用uu块时,块将复制(保留)变量,因此即使修改变量,块也可以访问旧对象。

    1
    2
    3
    4
    5
    6
    NSString* str = @"hello";
    void (^theBlock)() = ^void() {
        NSLog(@"%@", str);
    };
    str = @"how are you";
    theBlock(); //prints @"hello"

    在这两种情况下,您需要块:

    1.如果要修改块内的变量并希望它在块外可见:

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

    2.如果要在声明块后修改变量,并且希望块看到更改:

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

    __block是一种存储类型,用于使作用域变量可变,更坦率地说,如果用这个说明符声明一个变量,它的引用将被传递给块,而不是只读副本。有关详细信息,请参阅IOS中的块编程。


    希望这对你有帮助

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

    1
    2
    3
    4
    5
    6
    7
    8
    {
         int stackVariable = 1;

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

    它将给出一个类似"变量不可赋值"的错误,因为块中的堆栈变量在默认情况下是不可变的。

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


    从块语言规范:

    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.

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


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