Unable to understand block lexical area

To understand the lexical volume of a block, I write the following code

typedef int (^ MyBlock)(void); MyBlock b[3]; for (int i=0; i<3; i++) { b[i]=^{return i;}; } for (int i=0; i<3; i++) { NSLog(@"%d",b[i]()); } NSLog(@"----------------------------"); int j=0; b[0]=^{return j;}; j++; b[1]=^{return j;}; j++; b[2]=^{return j;}; for (int i=0; i<3; i++) { NSLog(@"%d",b[i]()); } 
  • first time o / p - 2.2.2
  • second time o / p - 0,1,2

I expect 2.2.2 to execute both blocks.

Can someone explain to me why this is so?

+6
source share
2 answers

I assume that you read bbums post on blocks and know that your code is wrong as you are not copying blocks from the stack to the heap.

That said:

 for (int i=0; i<3; i++) { b[i]=^{return i;}; } 

performs the following at each iteration:

  • Allocates space on the stack for a block variable. Let say that his memory address: A;
  • Creates a block on the stack and assigns its address (A) b[i] ;
  • At the end of the iteration, since the compound statement / region ( {} ) has ended, everything that was on the stack pops up and resets the stack pointer.

The stack grows at the beginning of each iteration and contracts at the end of each iteration. This means that all blocks are created in the same memory address, namely A. It also means that all elements of the array b ultimately point to the same block, namely the last block that was created. You can verify this by running the following code:

 for (int i = 0; i < 3; i++) { printf("%p", (void *)b[i]); } 

which should output something like:

 0x7fff5fbff9e8 0x7fff5fbff9e8 0x7fff5fbff9e8 

All elements point to the same block, the last of which is created in the memory address A = 0x7fff5fbff9e8.

On the other hand, when you do the following:

 b[0]=^{return j;}; j++; b[1]=^{return j;}; j++; b[2]=^{return j;}; 

There is no compound statement that defines the same area for all blocks. This means that every time you create a block, its address is further on the stack, effectively assigning a different address for each block. Since all blocks are different, they correctly capture the current value of the execution time j .

If you print the address of these blocks as described above, you should get a result similar to:

 0x7fff5fbff9b8 0x7fff5fbff990 0x7fff5fbff968 

indicating that each block has a different memory address.

+7
source

I use an array of blocks with b [i], not i, which is used inside each block to iterate. The blocks you define refer to i, which is used during the definition. And that I change to 2. Then you iterate over these blocks with a different i, but the block still refers to the original i (which now contains the value 2) that you used when defining the block, although I am already “dead” for the rest parts of the program. In the second case, your blocks also use a shared variable, but you change it before using it every time.

Key: The block is always associated with the variable that was used during the definition. I in the second for the loop is not the i referenced by the blocks.

Blocks can be called when the defining code is already dead. For this, reference variables have an "extended" live. They can also be moved to heap at runtime.

Take a look at WWDC 2010 video “Session 206 - Introducing Blocks and Grand Central Dispatch on iPhone.”

0
source

Source: https://habr.com/ru/post/892471/


All Articles