Details on gory can be found in the Block Implementation Specification .
The easiest way to explain with an example. Consider this simple function containing a simple block:
void outerFunction() { int x = 7; dispatch_block_t block = ^{ printf("%d\n", x); }; dispatch_sync(dispatch_get_main_queue(), block); }
Remember that dispatch_block_t is a typedef for void (^)(void) .
To compile this code, the compiler will first create two structure definitions:
struct Block_descriptor_1 { unsigned long reserved; unsigned long size; const char *signature; }; struct Block_literal_1 { void *isa; int flags; int reserved; void (*invoke)(void *); struct Block_descriptor_1 *descriptor; int x; };
Then it creates a global variable of type Block_descriptor_1 , which contains the size of Block_literal_1 and the encoding of the signature of the block type:
struct Block_descriptor_1 block_descriptor_1 = { .size = sizeof(struct Block_literal_1), .signature = " v4@ ?0" };
And he creates a function containing the block body:
void outerFunction_block_invoke(void *voidLiteral) { struct Block_literal_1 *literal = (struct Block_literal_1 *)voidLiteral; printf("%d\n", literal->x); }
Note that the body of the block was rewritten in such a way that access to the variable x from the enclosing area is now access to the element of the block literal.
Finally, the compiler overwrites the original function to create a block literal on the stack and to use the address of this block literal instead of a block:
void outerFunction2() { int x = 7; struct Block_literal_1 block_literal_1 = { .isa = __NSConcreteStackBlock, .flags = BLOCK_HAS_SIGNATURE, .invoke = outerFunction_block_invoke, .descriptor = &block_descriptor_1, .x = x }; dispatch_sync(dispatch_get_main_queue(), (__bridge dispatch_block_t)&block_literal_1); }
Note that a block literal begins with a pointer to a special Objective-C Class . This allows you to process block literature as an Objective-C object.
If you add the __block attribute to the local variable x , it becomes more complex. In this case, the compiler must create another structure for storing this variable along with information about this variable (for example, how to save and release it if the variable is a pointer to an object). All of this is explained in the specification that I linked at the top of this answer.