Rules for capturing a variable with a block in objective-C

What is the semantics of block capturing a variable in objective-C?

#import <Foundation/Foundation.h> #include <stdio.h> int main() { NSMutableArray *arr = [NSMutableArray array]; for (int i = 0; i < 100; ++i) { int j = i; [arr addObject:^(void) {printf("%d %d\n", i, j); }]; } for (void (^blk)(void) in arr) { blk(); } } 

I outlined this to print something like:

 100 0 100 1 ... 100 99 

Instead, it prints:

 99 99 99 99 ... 99 99 

How is it even possible that he interprets j as equal to 99 ? j doesn't even exist outside the for loop.

+5
source share
2 answers

Because you are not using ARC! Without it, your block is not copied. You are just lucky and it starts the last block every time.

+6
source

The reason you see 99 99 many times is simply due to undefined behavior.

Take the first for loop:

 for (int i = 0; i < 100; ++i) { int j = i; dispatch_block_t block = ^(void) {printf("%d %d\n", i, j); }; [arr addObject:block]; } 

[I pulled out the block for clarity.]

A block is created inside this loop. It is created on the stack and never moved to the heap, because there is no copy of the block for this.

Each time around a for loop, it is very likely (well, really, really) that the same stack space is used for this block. And then the address of the block (which is on the stack) is added to arr . The same address every time. But this is a new block implementation every time.

After exiting the first for loop, arr contains the same value 100 times. And this value points to the last block created, which is still on the stack. But this points to a block in the stack that can no longer be reached safely because it goes out of scope.

However, in the case of this example, the stack space occupied by the block by pure luck (OK, simple code) was not reused. Therefore, when you go and use the block, it "works."

The correct solution is to copy the block when it is added to the array. Either call copy , or let ARC do this for you. Thus, the block is copied to the heap, and you have a countable counted block that will work for as long as the array and the area in which it is created are needed.

If you want to learn more about how blocks work and understand this answer more deeply, I offer my explanations here:

http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/ http://www.galloway.me.uk/2012/10/a-look-inside- blocks-episode-2 / http://www.galloway.me.uk/2013/05/a-look-inside-blocks-episode-3-block-copy/

+3
source

All Articles