Change data from the parent area inside the send queue

According to the Concurrency Programming Guide:

When blocks are added to the send queue, these values โ€‹โ€‹should usually remain in read-only format. However, blocks that execute synchronously can also use variables that have the __block keyword added to return data back to the parent call area.

I changed the variables created outside the queue, but I never specified them using __block , so I wonder when and why. Or is it that instance variables are always inevitably changed by blocks, as if they have __block assigned to them from behind the scenes?

Update: I have to add that I use asynchronous queues, while the above says that variables can only be changed in synchronous queues (with __block )

+4
source share
2 answers

Access to the iVar instance iVar your class inside the block is interpreted by the compiler as self->iVar . Therefore, the block captures self , which does not change.

I am sure that the __block modifier __block works with dispatch_async , so this could be a documentation error.

ADDED

The following example shows how the __block variable can be used with dispatch_async :

 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); __block int total = 0; printf("address of total: %p\n", &total); // dispatch some (concurrent) blocks asynchronously: dispatch_async(queue, ^{ OSAtomicAdd32(5, &total); }); dispatch_async(queue, ^{ OSAtomicAdd32(7, &total); }); // Wait for all blocks to complete: dispatch_barrier_sync(queue, ^{ }); printf("address of total: %p\n", &total); printf("total=%d\n", total); 

Output:

 address of total: 0x7fff5fbff8f0 address of total: 0x100108198 total=12 

You can see that total copied from the stack to the heap when blocks are executed.

ADDED

I just found this in the Block Programming Guide. This explains why there is no problem using __block variables with asynchronous blocks.

__ Block variables live in a repository that is shared between the lexical region of the variable and all declared blocks and block copies or created within the lexical region of variables. Thus, to withstand the destruction of the stack frame, if any copies of the blocks declared in the frame go beyond the frame (for example, by placing somewhere for later execution). multiple blocks in a given lexical domain can simultaneously use a common variable.

As an optimization, block storage begins with the stack, as do the blocks themselves. If a block is copied using Block_copy (or in Objective-C when a copy is sent to the block), the variables are copied to the heap. Thus, the address of the __ block variable can change over time.

+1
source

A quote from Concurrency Programming Guide refers to variables that are created inside a function or method. The variables created inside them are created on the stack , which holds them until the function is called. In other words, when a function returns, its stack stack is destroyed along with the variables.

Objects in Objective-c are created on the heap so that they can live after the function returns, however when creating a string, for example:

 MyClass *object = [[MyClass alloc] init]; 

You create an object to be placed in the heap, but you also create an object variable that contains a pointer to your object on the heap. This variable is placed on the frame stack of the current method / function and will be deleted after it returns. Your object, if you do not release it, will not be deleted, even if the function has ended.

This is why it blocks the variables of the parent variable of the parent referenced by the internal blocks. They are copied to block private memory, because they can be destroyed at the end of a function call, and, as you know, a block can be used after that. To do this, you need to use the __block specifier to tell the block that it does not copy the variable from the stack and does not use it directly. Since these variables can be destroyed when the function returns, the Concurrency Programming Guide indicates that in this case only synchronous sending should be used, since it will ensure that the block will be executed before the function returns. EDIT: As Martin R correctly pointed out that __block variables __block not always used directly from the stack. As stated in this documentation , they are treated as pointers, and their address can be changed from the stack when copying a block (for example, when sending). The copied variables are placed in storage, which is divided between the blocks and the function, in order to extend the variable's lifetime. I think the reason it is argued that local variables should be used with dispatch_sync is because environment variables other than ARC are not saved * , thereby creating the risk of using a freed object. For the same reason, I think you are not using __block in front of static and instance variables.

Variables that instance variables or static variables do not live on the stack of any function, so they are not copied by the block, and you do not need the __block specifier. A static variable will work as long as the program starts, but the instance variable is destroyed when the object that holds this variable is destroyed. Therefore, blocks have a different function - all objects referenced inside the block will be stored for the lifetime of the block to ensure that the object will not be released unexpectedly.

+1
source

All Articles