美文网首页
block本质

block本质

作者: 有毒的程序猿 | 来源:发表于2018-12-24 11:28 被阅读4次
    1.C++源码预览
     int a = 10;
     void(^block)(void) = ^{
            NSLog(@"Hello, World! %d",a);
      };
      block();
    

    通过clang -rewrite-objc main.m生成cpp文件

    // 代码变为
    int a = 10;
    void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    
    // 一看是不是有点蒙蔽我们去掉强制装换来看一下
    
    int a = 10;
    void(*block)(void) = 
    &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, a); 
    // 这一句就是调用一个c的方法,并取这个方法的地址,赋值给一个block类型的指针
    
    block->FuncPtr(block);
    
    // 拿到这个block一个成员的FuncPtr方法并调用
    
    

    先看下这个东西__main_block_impl_0

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int a; // 声明一个和外面一样的变量,并且捕获
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    __main_block_impl_0 其实就是block的本质一个结构体,
    里面有个同名字的构造方法返回本身(c++语法).
    
    构造方法里
    impl.isa = &_NSConcreteStackBlock;   // 确定isa指向
    impl.Flags = flags;                  // 标识为0
    impl.FuncPtr = fp;                   // 代码块方法
    Desc = desc;                         // 描述
    
    构造函数传进来的参数都赋值给了__main_block_impl_0结构体的成员impl, 
    impl也是一个结构体
    
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    
    看到没有block也持有一个void *isa指针,所以说block是一个oc对象.
    
    

    之后看下这个东西__main_block_func_0 就是调用构造函数传进去的参数

    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
      int a = __cself->a; // 此参数可以从上面代码看出,是传的block
    
      NSLog((NSString *)&__NSConstantStringImpl__var_folders_sf_9x41px110wz4nbxh71bwvwzr0000gp_T_main_dd6554_mi_0,a);
    }
    
    这里正好是我们的打印代码,block里面的代码都会放在这里面等待调用
    

    所以说block其实是一个结构体,保存一个函数指针,指向我们写的代码块既一个c函数,等待我们调用.

    • block本质也是一个oc对象,内部也有一个isa指针.
    • block是封装了函数调用及函数调用环境的oc对象.
    2.捕获变量
    image.png
    // 大括号外面
    int age3 = 10;            // 全局变量
    static int age4 = 10;    // 全局变量静态
    
    // 大括号外面
    {
    auto int age1 = 10;       // oc默认是auto变量
    static int age2 = 10;    // 局部静态
    }
    

    通过源码看下两者的却别

    #import <Foundation/Foundation.h>
    
    int age3 = 30;
    static int age4 = 30;
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            auto int age1 = 10;
            static int age2 = 20;
            void(^block)(void) = ^{
                NSLog(@"Hello, World! %d%d%d%d",age1,age2,age3,age4);
            };
            block();
        }
        return 0;
    }
    

    c++

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      int age1;
      int *age2;
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age1, int *_age2, int flags=0) : age1(_age1), age2(_age2) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    int age1 = __cself->age1; // bound by copy
    int *age2 = __cself->age2; // bound by copy
    
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_sf_9x41px110wz4nbxh71b
    wvwzr0000gp_T_main_b2cff9_mi_0,age1,(*age2),age3,age4);
    }
    
    从上面源码看出,只捕获了age1和age2,而age3和age4是直接用的
    age1是值,age2是指针,所以age1捕获的是值age2捕获的是指针.
    
    3.block类型
    block类型.jpg block存储位置.png
    auto int age1 = 10;
    void(^block)(void) = ^{
         NSLog(@"Hello, World! %d%d%d%d",age1);
    };
    block();
    NSLog(@"%@",[block class]);
    
    [block class] // 可以直接获取block类型,从这一点也说明block是一个oc对象
    
    arc下系统会自动帮你把block从栈上拷贝到堆上
    既调用[block copy]
    

    相关文章

      网友评论

          本文标题:block本质

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