首页 > 代码库 > block 结构(1)

block 结构(1)

一个block其实是一个对象,有他自己的属性,结构如下

  • isa指针,所有对象都有该指针,用于实现消息传递等功能(ias一般指向父类、元类)
  • flags,用于按bit位表示一些block的附加信息
  • reserved,保留变量。
  • invoke,函数指针,指向具体的block实现的函数调用地址。
  • descriptor, 表示该block的附加描述信息,主要是size大小,以及copy和dispose函数的指针。
  • variables,capture过来的变量,block能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

     

我们借助  clang -rewrite-objc 命令反编译.m文件得到.cpp文件,.m包含以下代
-(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);}

 

得到部分源代码

 //这里应该是注册代码中的常量,下面会用到

#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};
//这里就是block对象的结构
//imp:函数指针,指向具体block实现的函数
//_person2:截获的变量
//isa、flags、funcptr、desc后面会说道。
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;  }
//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函数,可以拷贝到堆上
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*/);}
//对应的释放函数
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对象的描述信息(大小等等)
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};
//这是objc测试函数test
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);}

 

简单分析:
 1).block初始化,结合构造函数:
__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);
传入了参数:函数指针、block描述、外部变量_person2,这时候在block内部对_person2进行了深拷贝(其实我也没从哪里看出来到底是深拷贝,希望大神赐教)
2).执行block
((void (*)(__block_impl *, int))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, 1);

其实还是调用了block函数指针 所指向的函数__KDBlockTest__test3_block_func_0,并把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);    }

值得注意的的是,我们在执行之前对_person2修改,但是并没有对block内部产生影响,因为在构造block的时候,block内部对截获的变量已经做了深拷贝,执行block的时候,直接调用函数__KDBlockTest__test3_block_func_0,函数内部,是引用了block拷贝的_person2对象,我想这应该就是block截获变量的特性