ishahak ishahak - 4 months ago 15
iOS Question

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!

dan dan
Answer

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.