The essence of Block:
#import <Foundation/Foundation.h>int main () { void(^BLK) (void) =^{ printf ("Block"); Blk (); return 0 ;}
Use Clang to convert the block.
CLANG-REWRITE-OBJC Source code files
The block files formed after conversion are:
struct __block_impl { void *Isa; int Flags; int Reserved; void *funcptr;};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* desc;
__main_block_impl_0 (void *fp, struct __main_block_desc_0 *desc, int flags=0) {
Impl.isa = &_NSConcreteStackBlock;
Impl. Flags = flags;
Impl. funcptr = FP;
desc = desc;
}
};
static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {
printf ("Block");}
Static struct __main_block_desc_0 {
SIZE_T reserved;
size_t Block_size;
} __main_block_desc_0_data = { 0, sizeof(struct __main_block_impl_0)};
int Main () {
void(*BLK) (void) = ((void (*) ()) &__main_block_impl_0 ( (void *) __main_ Block_func_0, &__main_block_desc_0_data));
((void (*) (__block_impl *)) ((__block_impl *) blk)->funcptr) ((__block_impl *) blk);
return 0;
}
Here's a detailed analysis of these source code:
First we see
^{printf ("Block");
After conversion is called
Static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {printf (" Block");}
As shown above, the anonymous function used by block is actually converted to the C-language function processing, and the _cself in the function is a pointer to the _MAIN_BLOCK_FUNC_0 struct.
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* desc;
With two member variables, the _BLOCK_IMPLD code is as follows:
struct __block_impl { void *Isa; int Flags; int Reserved; void *funcptr;};
The second member variable is
__MAIN_BLOCK_DESC_0: The code is as follows:
Static struct __main_block_desc_0 {
SIZE_T reserved;
size_t Block_size;
}
This includes the area required for future version upgrades and the size of the block.
Let's take a look at the code that initializes the struct containing the data:
__main_block_impl_0 (voidstructint flags=0) { = &_ Nsconcretestackblock; = flags; = fp; = desc; }
In this case the Nsconcretestackblock is used to initialize, and then we call the constructor:
void (*BLK) (void) = (( Void (*) ()) &__main_block_impl_0 (void *) __main_block_func_0, &_ _main_block_desc_0_data));
Because the conversion is too much to understand, so we get rid of the transformation of the part, so that the result is:
struct _main_block_impl_0 tmp=_main_block_impl_0 (_main_block_func_0,&_main_block_desc_data); struct _main_block_impl_0 *blk=&tmp;
So that we can clearly see that
void (^BLK) (void) =^{printf ("Block");
This statement implements the two variables of _main_block_impl_0, a function function, a desc, and the block type object generated by the block syntax is then assigned to the BLK, which is equivalent to assigning the pointer of the instance to BLK,_MAIN_BLOCK_DESC_ Data is primarily initialized for the size of the _main_block_impl_0 instance of the struct.
Blk ();
This part of the code is converted to
((void (*) (__block_impl *)) ((__block_impl *) blk)->funcptr) ((__block_impl *) blk);
As we get rid of the parts of the transformation are:
(*BLK)->impl. Funcptr (BLK)
This is actually the simplest function pointer call function, as we have just confirmed, in the calling function we see that the block is passed as a parameter.
So what exactly is Nsconcretestackblock?
In order to understand him first we need to understand the OC class and the essence of the object, in fact, the so-called block is the object, "id" This variable is used to store OC object, Nsconcretestackblock is equivalent to C struct body instance, when the block as OC object processing, The information for this class is placed at the Nsconcretestackblock.
Block realizes the essence of-block