2

So thanks to this post, I'm familiar with the __block keyword. It basically means to NOT copy the instance, but rather just passing its original reference.

The benefits I see for doing that are:

  • Any modification made to the instance inside the block will reflect in the original instance.
  • Avoiding the "waste" of copying the instance we're gonna use inside the block.

I am curious, though, how much should we really bother with this declaration, for example, if I have this method that receives a callback block as a parameter:

-(void)doSomethingWithCallback:(MyTypeOfCallback)callback;

and let's say this method calls another method with a callback as a parameter. Is it then worthwhile to __block the original callback parameter if we want to call it inside the next method:

-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
    __block MyTypeOfCallback blockCallback = callback;
    [self doAnotherThingWithBlock:^(BOOL result) {
       if (result)
           blockCallback();
    }];
}

or should I simply call the original block parameter inside the next method?

-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
    [self doAnotherThingWithBlock:^(BOOL result) {
       if (result)
           callback();
    }];
}

I'm asking because it makes sense to include the __block option, but then again I find myself doing it in too many places and it's starting to take many code lines.

BTW, this also goes for every any other type of parameter, not only blocks.

Community
  • 1
  • 1
mllm
  • 17,068
  • 15
  • 53
  • 64
  • 9
    There is no reason at all to use `__block` in your example. The use of `__block` is when a variable declared outside a block needs to be modified inside a block. You are not making any attempt to reassign `callback` so there is no purpose to the `__block` variable `blockCallback`. – rmaddy Aug 08 '15 at 19:35
  • Ok, and what about avoiding the copying of that instance? – mllm Aug 08 '15 at 19:45
  • 3
    That's not something you should worry about. Let the compiler do its thing. Premature optimization by the developer leads to more issues than it ever fixes. – rmaddy Aug 08 '15 at 19:49
  • 2
    +1 Beside this, capturing values (aka copying) is a fundamental concept of a closure and using `__block` is the exception. You should have reasons to use `__block`. – Amin Negm-Awad Aug 09 '15 at 05:28

2 Answers2

3

It's basically telling the compiler to NOT copy the instance

No. __block has nothing to do with "instances". __block is a storage qualifier for variables.

__block on a variable means that the same copy of the variable will be shared between the original scope any any blocks that capture it (as opposed to each block getting a separate copy of the variable when it captures non-__block variables).

In your case, you have a variable of type MyTypeOfCallback, a (I'm guessing) pointer-to-block type. In the first piece of code, you make it __block, so there is a single pointer variable whose state is shared between the function scope and the block (which captures it). If either scope assigns to the pointer variable, the change would be visible in the other scope.

In the second piece of code, you make it non-__block, and when the block literal is executed, it copies the value of that pointer at that moment into a separate pointer variable in its own structure, so that you have two copies of the pointer. If you afterwards assign to the pointer variable in the function scope, the change would not be visible to the block, since it has its own copy.

In this case, there is no difference between the two, because you never assign to the pointer variable in question after initialization. It is basically a constant variable, and one copy or two copies makes no difference.

newacct
  • 119,665
  • 29
  • 163
  • 224
0
-(void)doSomethingWithCallback:(MyTypeOfCallback)callback
{
    __block MyTypeOfCallback blockCallback = callback;
    [self doAnotherThingWithBlock:^(BOOL result) {
       if (result)
           blockCallback();
    }];
}

You can call callback from in block so

-(void)doSomethingWithCallback:(void(^)(void))callback
{
    __block typeof(callback)blockCallback = callback;

    [self doAnotherThingWithBlock:^(BOOL result) {
       if (result)
           blockCallback();
    }];
}