477

What exactly does the __block keyword in Objective-C mean? I know it allows you to modify variables within blocks, but I'd like to know...

  1. What exactly does it tell the compiler?
  2. Does it do anything else?
  3. If that's all it does then why is it needed in the first place?
  4. Is it in the docs anywhere? (I can't find it).
royhowie
  • 11,075
  • 14
  • 50
  • 67
mjisrawi
  • 7,846
  • 3
  • 24
  • 27
  • 3
    check [here](http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html), and the "Blocks and variables" section. –  Aug 16 '11 at 15:41
  • 1
    possible duplicate of [Objective-C block syntax - can someone explain this?](http://stackoverflow.com/questions/6392626/objective-c-block-syntax-can-someone-explain-this) –  Aug 16 '11 at 15:42
  • @Vincent ack, thanks I forgot about that section! I'll give it a look. – mjisrawi Aug 16 '11 at 15:45
  • 1
    @Code Monkey: I was asking specifically about the keyword, not the syntax in general. So don't think it's really a duplicate. – mjisrawi Aug 16 '11 at 15:46
  • 3
    @Code Monkey: No, this is not a duplicate. The question you mention doesn't talk about `__block` at all. – DarkDust Aug 16 '11 at 15:50
  • 3
    And if someone is wondering how Objective-C's `__block` should translate to Swift: *”Closures [in Swift] have similar capture semantics as blocks [in Objective-C] but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of __block in Objective-C is the default behavior for variables in Swift.”* From Apple's book: Using Swift with Cocoa and Objective-C (Swift 2.2). – Jari Keinänen Apr 11 '16 at 11:21

8 Answers8

572

It tells the compiler that any variable marked by it must be treated in a special way when it is used inside a block. Normally, variables and their contents that are also used in blocks are copied, thus any modification done to these variables don't show outside the block. When they are marked with __block, the modifications done inside the block are also visible outside of it.

For an example and more info, see The __block Storage Type in Apple's Blocks Programming Topics.

The important example is this one:

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'
}

In this example, both localCounter and localCharacter are modified before the block is called. However, inside the block, only the modification to localCharacter would be visible, thanks to the __block keyword. Conversely, the block can modify localCharacter and this modification is visible outside of the block.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • 12
    Excellent, concise explanation, and a very helpful example. Thanks! – Evan K. Stone Feb 01 '13 at 22:42
  • 1
    How does the aBlock modify localCounter? It only seems to modify CounterGlobal. Thanks – CommaToast Oct 14 '13 at 23:53
  • 8
    It does not modify `localCounter`, but it does modify `localCharacter`. Also, pay attention to the value `localCounter` has in the block: it's 42, even though the variable gets increased *before* the block is called but *after* the block was created (that's when the value got "captured"). – DarkDust Oct 15 '13 at 07:16
  • 1
    That's a helpful explanation - though - can you explain what seem to be contradictory statements in your explanation? You say above that "aBlock modifies...localCounter" and then in the comments you say "[aBlock] does NOT modify localCounter." Which is it? If it is "not modified" then should your answer be edited? – Praxiteles Jun 15 '14 at 08:14
  • 4
    In general, vars without __block would be captured by value and packed into the block's "environment", when the block is created. But __block vars won't be captured, whenever they're used inside or outside of a block, they're referenced as is. – addlistener Dec 24 '14 at 17:50
  • Does it do anything else? Could you please explain __block before a object of type NSObject? – Robert Jun 06 '19 at 09:48
30

@bbum covers blocks in depth in a blog post and touches on the __block storage type.

__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.
...

As for use cases you will find __block is sometimes used to avoid retain cycles since it does not retain the argument. A common example is using self.

//Now using myself inside a block will not 
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;
Cœur
  • 37,241
  • 25
  • 195
  • 267
Joe
  • 56,979
  • 9
  • 128
  • 135
  • See this post for more info about the retain cycle issue: http://benscheirman.com/2012/01/careful-with-block-based-notification-handlers. Would `__weak` suffice in this specific case as well? It's bit clearer perhaps... – Hari Honor Aug 10 '12 at 18:41
  • 18
    Finally the claim that __block can be used to avoid strong reference cycles (aka retain cycles) is plain wrong in an ARC context. Due to the fact that in ARC __block causes the variable to be strongly referenced, it's actually more likely to cause them.http://stackoverflow.com/a/19228179/189006 – RK- Apr 08 '14 at 08:10
15

When you don't use __block, the block copies the variable (call-by-value), so even if you modify the variable elsewhere, the block doesn't see the changes.

__block makes the blocks keep a reference to the variable (call-by-reference).

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

In these 2 cases you need __block:

  1. 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"
    
  2. 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"
    
  • I will also mention that an automatic variable marked with `__block` gets converted by the compiler into an autoreleased object, whose lifespan lasts as long as the block does, possibly beyond the scope it is declared in. Furthermore, it gets created every time, so each instance of the `theBlock` created will refer to a different `str` variable. – James Bucanek Jan 14 '23 at 19:23
10

__block is a storage qualifier that can be used in two ways:

  1. Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).

  2. In MRC, __block can be used to avoid retain object variables a block captures. Careful that this doesn't work for ARC. In ARC, you should use __weak instead.

You can refer to apple doc for detailed information.

Mindy
  • 429
  • 4
  • 6
7

__block is a storage type that is use to make in scope variables mutable, more frankly if you declare a variable with this specifier, its reference will be passed to blocks not a read-only copy for more details see Blocks Programming in iOS

Forge
  • 6,538
  • 6
  • 44
  • 64
2

hope this will help you

let suppose we have a code like:

{
     int stackVariable = 1;

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

it will give an error like "variable is not assignable" because the stack variable inside the block are by default immutable.

adding __block(storage modifier) ahead of it declaration make it mutable inside the block i.e __block int stackVariable=1;

Ky -
  • 30,724
  • 51
  • 192
  • 308
Anurag Bhakuni
  • 2,379
  • 26
  • 32
2

From the Block Language Spec:

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.

For details on what a __block variable should compile to, see the Block Implementation Spec, section 2.3.

Community
  • 1
  • 1
Martin Gordon
  • 36,329
  • 7
  • 58
  • 54
0

It means that the variable it is a prefix to is available to be used within a block.

Rich Allen
  • 59
  • 7