A block is actually an object with its own attributes. The structure is as follows:
- ISA pointer. All objects have this pointer for message transmission and other functions (IAS generally points to the parent class and metadata class)
- Flags, used to indicate additional block information by bit
- Reserved, reserved variable.
- Invoke, function pointer, pointing to the function call address implemented by the specific block.
- Descriptor, indicating the additional description of the block, mainly the size and pointer of the copy and dispose functions.
- Variables, a variable from capture, block can access its external local variables because these variables (or the address of the variable) are copied to the struct.
We use the clang-rewrite-objc command to decompile the. M file to obtain the. cpp file. M contains the following generation
-(void )test3{ NSString *_person2=@"person2"; NSLog(@"block init:%@,%p,%p",_person2,&_person2,_person2); void (^myBlock)(int) = ^(int num) { NSLog(@"block excuteing:%@,%p,%p",_person2,&_person2,_person2); }; _person2=@"person22"; NSLog(@"block excutebefore:%@,%p,%p",_person2,&_person2,_person2); myBlock(1); NSLog(@"block excuteafter:%@,%p,%p",_person2,&_person2,_person2);}
Obtain some source code
// Here it should be a constant in the registration code, which will be used below
#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_0 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"KDBlockTest dealloc",19};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"person2",7};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_2 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"block init:%@,%p,%p",19};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_3 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"block excuteing:%@,%p,%p",24};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_4 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"person22",8};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_5 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"block excutebefore:%@,%p,%p",27};static __NSConstantStringImpl __NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_6 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"block excuteafter:%@,%p,%p",26};// Here is the structure of the block object
// Imp: function pointer pointing to the function implemented by the specific block
// _ Person2: intercepted variable
// Isa, flags, funcptr, and desc will be mentioned later.
struct __KDBlockTest__test3_block_impl_0 { struct __block_impl impl; struct __KDBlockTest__test3_block_desc_0* Desc; NSString *_person2; __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, NSString *__person2, int flags=0) : _person2(__person2) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }
// Functions implemented by block
static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) { NSString *_person2 = __cself->_person2; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_3,_person2,&_person2,_person2); }
// Copy function, which can be copied to the stack
static void __KDBlockTest__test3_block_copy_0(struct __KDBlockTest__test3_block_impl_0*dst, struct __KDBlockTest__test3_block_impl_0*src) {_Block_object_assign((void*)&dst->_person2, (void*)src->_person2, 3/*BLOCK_FIELD_IS_OBJECT*/);}
// Corresponding release function
static void __KDBlockTest__test3_block_dispose_0(struct __KDBlockTest__test3_block_impl_0*src) {_Block_object_dispose((void*)src->_person2, 3/*BLOCK_FIELD_IS_OBJECT*/);}
// Block Object Description (size, etc)
static struct __KDBlockTest__test3_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __KDBlockTest__test3_block_impl_0*, struct __KDBlockTest__test3_block_impl_0*); void (*dispose)(struct __KDBlockTest__test3_block_impl_0*);} __KDBlockTest__test3_block_desc_0_DATA = { 0, sizeof(struct __KDBlockTest__test3_block_impl_0), __KDBlockTest__test3_block_copy_0, __KDBlockTest__test3_block_dispose_0};
// This is the objc test function.
static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) { NSString *_person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_1; NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_2,_person2,&_person2,_person2); void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, 570425344); _person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_4; NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_5,_person2,&_person2,_person2); ((void (*)(__block_impl *, int))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, 1); NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_6,_person2,&_person2,_person2);}
Simple Analysis: 1) block initialization, combined with constructors:
__KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, NSString *__person2, int flags=0) : _person2(__person2) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }
void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, 570425344);
Passed in parameters: function pointer, block description, external variable _ person2. At this time, _ person2 was deeply copied in the block (in fact, I didn't see from where it was actually a deep copy, hope you can enlighten me) 2 ). execute Block
((void (*)(__block_impl *, int))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, 1);
In fact, the function _ kdblocktest _ test3_block_func_0 pointed to by the block function pointer is called, and the block itself is passed as a parameter.
static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) { NSString *_person2 = __cself->_person2; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_51f509_mi_3,_person2,&_person2,_person2); }
It is worth noting that we modify _ person2 before execution, but it does not affect the interior of the block, because when constructing the block, the block has already made a deep copy of the intercepted variables. When the block is executed, the function _ kdblocktest _ test3_block_func_0 is called directly. Inside the function, the _ person2 object copied by the block is referenced, I think this should be the feature of block interception variables.