美文网首页iOS-block知识
iOS-Block02-小谈block的底层数据结构

iOS-Block02-小谈block的底层数据结构

作者: IBigLiang | 来源:发表于2019-08-09 17:23 被阅读0次

    在写这篇文章的时候,距离上一篇写block的文章已经过了很久了iOS- 谈谈自己知道的block(菜鸟的总结)。笔者也是想再次总结一些学习成果
    这篇文章,主要是要分析下,block在系统编译之后,底层的展现到底是一个怎样的形式。首先我们还是通过clang的方式来编译我们的main.m文件,从而得到main.cpp文件。在cpp文件中,笔者只挑选出跟block有关的核心部分。首先,我们先来看看main.m的main函数部分:

      int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
           void (^block)(void) = ^{
                NSLog(@"这是一个block");
            };
            
            block();
            
        }
        return 0;
    }
    

    大家可以看到这是一个最简单的block定义和使用;然后我们再来看看cpp中main函数部分:

    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
    
           void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    
            ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    
        }
        return 0;
    }
    

    乍一看可能大家看不懂,因为有很多(),这里其实涵盖了很多c++类型的强制转换,简化完之后的代码如下:

    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
    
            void (*block)(void) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA));
            block->FuncPtr(block);
    
        }
        return 0;
    }
    

    然后我们再看关键的几个地方:
    1> __main_block_impl_0 这个其实我们不难找到,在cpp文件中已经定义了,是一个结构体:

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

    所以,由此可见

     &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA));
    

    就是结构体的初始化,然后返回这个结构体的指针地址给block.
    2> 再看这个结构体传入的两个参数 __main_block_func_0 / __main_block_desc_0_DATA 这两个在cpp中也是有所定义:

    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
                NSLog((NSString *)&__NSConstantStringImpl__var_folders_tv_bzqp7v7d453fs34hx6hm6k9m0000gp_T_main_37c1f9_mi_0);
            }
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
    

    也不难看出,__main_block_func_0这个函数就是我们block中的nslog部分, __main_block_desc_0这个结构体包含了我们block对应的大小
    3> 接下来解释下 block->FuncPtr(block) block对应的是__main_block_impl_0的地址,那block的地址其实就是__main_block_impl_0的第一个参数(struct __block_impl impl;)的地址,而第一个参数,我们可以继续在cpp中寻找:

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

    而这个__block_impl结构体中就包含了FuncPtr,所以block->FuncPtr(block);可以这么写, 等价于 __main_block_func_0(block)
    到此为止,大家应该对block的底层数据结构有所了解,当然有兴趣的同学可以试着去修改block,可以带参数编写,然后再去看看cpp文件中block不同的情况。有关于源码笔者就不写链接了,如果不懂clang的同学可以看下笔者之前的文章中有写,就是在main.m文件所在的文件夹中,执行一个中端的命令行:

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o mian-64.cpp
    

    相关文章

      网友评论

        本文标题:iOS-Block02-小谈block的底层数据结构

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