zoukankan      html  css  js  c++  java
  • iOS 技术篇:从使用到了解block底层原理 (二)

    block实质

    序言

    上篇文章中主要通过简单的demo展示了block的使用场景,本篇将基于上篇文章iOS 技术篇:从使用到了解block底层原理 (一)进一步了解block底层的实现原理。

    block作为一种"带有自动变量值的匿名函数",在实际编译时,我们无法转换成我们能够理解的源代码,但clang(LLVM编译器)具有转化为我们可读源代码的功能。终端输入如下命令行,可获取.cpp文件。

        clang -rewrite-objc 源代码文件名

    在main.m中实现如下

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            void(^myBlock)(void)=^{
                NSLog(@"testtest");
            };
            myBlock();
        }
        return 0;
    }

    通过clang我们获取到main.cpp 文件,打开文件我们可以看到大约10w行代码,当然我们不用从头到尾细细分析每块的功能。我们只需要看最后几行然后步步分析就可以。

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

    在main函数入口这里我们可以看到我们原实现block被转化为了另一种方式展示。不要着急看不到,从这里开始一步步分析。

    void(*myBlock)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

    通过全局搜索可以看到__main_block_impl_0的内部结构是:

    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;
      }
    };

    这里包含了两个结构体block_impl和main_block_desc_0,

    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    
    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_impl_0 结构声明
    __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;
      }

    不难看出: 1.main_block_impl_0就是block的一个C++的实现,_0代表是main中的第几个block,里面包含了保留值reserved和大小Block_size。 2.block_impl 就是block的内部实现。其中包含了 isa指针、flags标示、reserved保留值和funcPtr定义类型 (ps:_NSConcreteStackBlock相当于class_t结构体实例 想知道可以自己了解下)。

    从这里我们可以大概看出main_block_impl_0就是传了两个值main_block_func_0和&main_block_desc_0_DATA。一个是func结构体,另一个是desc指针。 以上就是初始化main_block_impl_0结构体成员的源代码。 接下来,将我们原来看到不太容易理解的__main_block_impl_0通过以上分析可以将

     void(*myBlock)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    

    转化为:

        struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
        struct __main_block_impl_0*myBlock = &tmp;

    这样就容易理解了,该源代码将main_block_impl_0 结构体类型的自动变量,即栈上生成的main_block_impl_0结构体实例的指针,赋值给__main_block_impl_0结构体指针类型的变量myBlock。 而
    myBlock();的底层实现如下:

    ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);

    转化之后就是

    (*myBlock->impl.FuncPtr)(myBlock);

    这就是简单的函数指针调用函数。

    可以理解为:有block语法转化的__main_block_func_0函数的指针被赋值成员变量FuncPtr中。

    到此也就了解了block的实质。

  • 相关阅读:
    二叉查找树详解
    探索推荐引擎内部的秘密
    个性化推荐漫谈
    网站的可扩展架构
    网站伸缩性架构--数据存储服务器集群的伸缩性设计
    SQL Server 分组后取Top N
    SQL SERVER 查询特定的前几条数据
    数据库的事务处理必须满足ACID原则,ACID分别是指什么
    String在JAVA里是固定长度的吗?为什么可用“+”连接
    怎样取得数组对象和arralist 的长度
  • 原文地址:https://www.cnblogs.com/lovemargin/p/11945320.html
Copyright © 2011-2022 走看看