2
votes

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.

2
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
Ok, and what about avoiding the copying of that instance? - mllm
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
+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

2 Answers

3
votes

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.

0
votes
-(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();
    }];
}