Block底层结构分析

Block底层结构分析

定义

block 是封装了函数调用及函数调用环境的OC对象

源码

//全局静态变量
static NSString* name_ = @"你好";
//全局自动变量
double height_ = 175.0;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //局部静态变量
        static int age = 10;
        //局部自动变量
        NSString *gender = @"男";
        
        double (^block)(int, int) = ^(int a, int b) {
          
            NSLog(@"局部变量:%@",gender);
            NSLog(@"局部静态变量:%d",age);
            NSLog(@"全局静态变量:%@",name_);
            NSLog(@"全局自动变量:%.f",height_);
            return a * b * age * height_;
        };
        int c = block(10, 10);
    }
    return 0;
}

clang指令后的cpp文件代码

通过代码可以看到,block实质上是一个由__main_block_impl_0生成的结构体对象指向的地址。
block是通过该地址的funcPtr指向的__main_block_func_0来调用;

__main_block_impl_0 构造函数中对应的参数分别是:

  • __main_block_func_0,
  • __main_block_desc_0_DATA,
  • gender
  • (__Block_byref_age_0 *)&age,
  • 570425344
int main(int argc, const char * argv[]) {

    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        static int age = 10;
        NSString *gender = (NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_1;
        double (*block)(int, int) = ((double (*)(int, int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, gender, &age, 570425344));
        int c = ((double (*)(__block_impl *, int, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 10, 10);
    }
    return 0;
}

__main_block_impl_0结构体

可以发现 全局静态变量name_和全局自动变量 height_ 没有被捕获,该结构体中被捕获的成员有局部自动变量gender和局部静态变量age

//全局静态变量不截获
static NSString* name_ = (NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_0;
//全局自动变量不截获
double height_ = 175.0;

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  //局部自动变量截获
   NSString *gender;
  //局部静态变量截获
  int *age;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_gender, int *_age, int flags=0) : gender(_gender), age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

__block_impl 结构体

从结构体中能发现isa指针,说明block本质上就是OC对象

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};  

__main_block_func_0 方法

观察__main_block_func_0方法,其中,gender和age都是通过__cself指针来获取,其中__cself的类型为__main_block_impl_0

  • FuncPtr 函数调用方法
  • copy 方法
  • dispose 方法
static double __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
  NSString *gender = __cself->gender; // bound by copy
  int *age = __cself->age; // bound by copy

      NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_2,gender);
      NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_3,(*age));
      NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_4,name_);
      NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_3c5203_mi_5,height_);
      return a * b * (*age) * height_;
 }

__main_block_desc_0 结构体

  • 保留字段
  • blockSize
  • copy方法
  • dispose方法
static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->gender, (void*)src->gender, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->gender, 3/*BLOCK_FIELD_IS_OBJECT*/);}

__block修饰后

__main_block_impl_0 结构体成员中多了一个__Block_byref_sex_0 类型的sex

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  NSString *gender;
  int *age;
  __Block_byref_sex_0 *sex; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_gender, int *_age, __Block_byref_sex_0 *_sex, int flags=0) : gender(_gender), age(_age), sex(_sex->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static double __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
  __Block_byref_sex_0 *sex = __cself->sex; // bound by ref
  NSString *gender = __cself->gender; // bound by copy
  int *age = __cself->age; // bound by copy

     NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_2,gender);
     NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_3,(*age));
     NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_4,name_);
     NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_5,height_);
     NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_6,(sex->__forwarding->sex));
     return a * b * (*age) * height_;
}

__Block_byref_sex_0结构体

注意该结构体中的__forwarding指针

struct __Block_byref_sex_0 {
  void *__isa;
__Block_byref_sex_0 *__forwarding;
 int __flags;
 int __size;
 int sex;
};

由__main_block_func_0中(sex->__forwarding->sex) sex的取值方式

可以知道通过__block 修饰过的局部变量,会生成一个__Block_byref_sex_0结构体,其中的__forwarding指针指向结构体自身
如果是栈上的block,取值通过forwading指针找到对应的__Block_byref_sex_0 结构体 取出对应的sex变量
如果是堆上的block,forwarding指针会指向堆上的block,而堆上的block自身的__forwarding指针找到对应的__Block_byref_sex_0 结构体 取出对应的sex变量
这样能保证无论在堆上还是在栈上,通过__block修饰过的变量,通过__forwarding指针总能被正确的找到

static double __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
    __Block_byref_sex_0 *sex = __cself->sex; // bound by ref
    NSString *gender = __cself->gender; // bound by copy
    int *age = __cself->age; // bound by copy
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_2,gender);                      
    NSLog((NSString*)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_3,(*age)); 
    NSLog((NSString     
 *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_4,name_);
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_5,height_);
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_rz_d1jw96h527v_b9sn9cq2yszr0000gn_T_main_4c84f9_mi_6,(sex->__forwarding->sex));
    return a * b * (*age) * height_;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。