ishahak
ishahak

Reputation: 6795

A Tricky Objective-C Blocks Behavior

I'd be glad to get explanation for the following behavior:

typedef void (^MyBlock)(void);
MyBlock g_ary[4];

int runBlockParam2(MyBlock callbackBlock, int num) {
    g_ary[num] = callbackBlock;
    return num+100;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int i;
        for (i=0; i<4; i++) {
            __block int j;
            int k = runBlockParam2(^{
                NSLog(@"in the block i=%i, j=%i", i, j);
            }, i);
            j=k;
        }
        for (i=0; i<4; i++) {
            g_ary[i]();
        }
    }
    return 0;
}

The above code shows the following output: in the block i=0, j=100 in the block i=1, j=101 in the block i=2, j=102 in the block i=3, j=103

Why is j modified by the assignment which follows the block?

It is interesting to mention that if we remove the __block modifier, we will get this: in the block i=0, j=0 in the block i=1, j=100 in the block i=2, j=101 in the block i=3, j=102

I'll appreciate any explanation to the above behavior!

Upvotes: 1

Views: 97

Answers (2)

dopcn
dopcn

Reputation: 4218

with __block the j variable will be passed into block as a pointer so if you call the block after the assignment j=k j is 100 now.

without __block only the j variable's value is passed into block. block itself couldn't change j after the block definition in which the value is passed. so j is 0

Upvotes: 0

dan
dan

Reputation: 9825

The __block storage type causes any changes to the variable outside of the block to be seen inside of the block and vice-versa. Your j = k line runs before the block itself is run in your second for loop so the block sees j after it has been assigned.

Removing the __block causes the block to capture the value of j as it is when the block is created which is before the assignment. You're invoking undefined behavior after removing the __block because you are capturing j before it has been initialized which leads to the strange output.

If you change your declaration to int j = 0 then the log statements would all show j=0 as you would expect.

Upvotes: 3

Related Questions