美文网首页
block的生成与调用记录

block的生成与调用记录

作者: nunca | 来源:发表于2018-11-26 18:01 被阅读0次
void nc_test() {
    
    void (^block1)(NSString *) = ^(NSString *str_a){
        NSLog(@"----%@",str_a);
    };
    block1(@"abc");  


    int (^block2)(int) = ^(int a){
        return a*2;
    };  
    int b = block2(123);
 
}

用clang -rewrite-objc main.m转化上面代码

void nc_test() {


    void (*block1)(NSString *) = ((void (*)(NSString *))&__nc_test_block_impl_0((void *)__nc_test_block_func_0, &__nc_test_block_desc_0_DATA));

    ((void (*)(__block_impl *, NSString *))((__block_impl *)block1)->FuncPtr)((__block_impl *)block1, (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2);


    int (*block2)(int) = ((int (*)(int))&__nc_test_block_impl_1((void *)__nc_test_block_func_1, &__nc_test_block_desc_1_DATA));

    int b = ((int (*)(__block_impl *, int))((__block_impl *)block2)->FuncPtr)((__block_impl *)block2, 123);

}

先关注下block1

查看与block1相关的几个结构:

struct __nc_test_block_impl_0 {
  struct __block_impl impl;
  struct __nc_test_block_desc_0* Desc;
  __nc_test_block_impl_0(void *fp, struct __nc_test_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
    }

static struct __nc_test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __nc_test_block_desc_0_DATA = { 0, sizeof(struct __nc_test_block_impl_0)};

回到block1的初始化:
    void (*block1)(NSString *) = ((void (*)(NSString *))&__nc_test_block_impl_0((void *)__nc_test_block_func_0, &__nc_test_block_desc_0_DATA));

可以看到是通过__nc_test_block_impl_0() 函数生成了一个对象再强转为(void (*)(NSString *))类型然后赋值给block1。

查看__nc_test_block_impl_0()

struct __nc_test_block_impl_0 {
  struct __block_impl impl;
  struct __nc_test_block_desc_0* Desc;
  __nc_test_block_impl_0(void *fp, struct __nc_test_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

__nc_test_block_impl_0()是__nc_test_block_impl_0的构建函数,调用时需要传入两个必传参数(void *fp, struct __nc_test_block_desc_0 *desc)
__nc_test_block_impl_0结构体下包含两个子结构,分别为__block_impl、__nc_test_block_desc_0类型

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

isa指针指向&_NSConcreteStackBlock,代表block的类型
FuncPtr指向的是block中内容的实现地址,调用block时真正调用的方法地址,__nc_test_block_impl_0结构体构建时第一个参数void *fp,就是赋值给FuncPtr的。

static struct __nc_test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __nc_test_block_desc_0_DATA = { 0, sizeof(struct __nc_test_block_impl_0)};

__nc_test_block_desc_0主要存储了block的大小,此处在编译时就构建了一个__nc_test_block_desc_0类型的对象__nc_test_block_desc_0_DATA,
也就是block1生成时调用__nc_test_block_impl_0()时传入的两个参数之一(&__nc_test_block_desc_0_DATA),另一个参数是(void *)类型的__nc_test_block_func_0

static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
    }

所以block1的初始化就是通过__nc_test_block_impl_0结构体的构建函数,生成一个__nc_test_block_impl_0的对象。

再看block1的调用:
    ((void (*)(__block_impl *, NSString *))((__block_impl *)block1)->FuncPtr)((__block_impl *)block1, (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2);

首先关于后面一长串( (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2),由于调用block时传入的参数是@"abc",为常量字符串,那一串则为常量字符串的存储地址。
然后去掉大量的类型转换:
((block1)->FuncPtr)(block1,&@"abc" );
也就是对block1结构体下的FuncPtr指向的函数的直接调用。也就是直接调用了初始化block1时传入的第一个参数__nc_test_block_func_0

static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
    }

关于长长的那两串都是代表代码中出现的常量字符串("abc"、"----%@"):

static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"----%@",6};
static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"abc",3};

相关文章

  • block的生成与调用记录

    用clang -rewrite-objc main.m转化上面代码 先关注下block1 查看与block1相关的...

  • Block是否循环引用

    判断block 内部是否循环引:自己持有对象是否持有自己。 1对象不持有block 2对象持有block 下面生成调用

  • Block常见使用总结(传值/作为参数/作为返回值等)

    来做个block的笔记。 block定义 block类型 block传值 block作为参数的方法定义与调用 bl...

  • iOS-Block的递归调用

    在看线程锁时,无意间看到block的递归调用,之前一直没有想怎么进行block递归调用,这里记录一下。

  • Block探究

    block的原理是怎样?本质是什么? block本质上也是一个OC对象,block是封装了函数调用与及调用环境的O...

  • iOS面试 -- Block相关重点

    Block的本质 Block是将函数及其上下文封装起来的对象 Block调用 Block调用就是函数的调用 截获变...

  • block 基本使用

    一、函数指针的作用 二、block的定义与调用方式 三、typedef block 四、block 修饰符 五、b...

  • block

    什么是block:block是将函数及其上下文封装起来的对象什么是block调用:block调用即是函数的调用 终...

  • Block详解-小码哥

    block本质 block的本质是封装了函数调用和函数调用环境的OC对象。 block结构 Block_layou...

  • Block嵌套导致的循环引用

    self -> obj -> block这种情况会导致self与block的循环引用 根据clang命令生成的c+...

网友评论

      本文标题:block的生成与调用记录

      本文链接:https://www.haomeiwen.com/subject/oowbqqtx.html