iOS源码解析:Block的本质

栏目: C++ · 发布时间: 5年前

内容简介:Block在iOS开发中的用途非常广,今天我们就来一起探索一下Block的底层结构。下面是一个没有参数和返回值的简单的Block:为了探索Block的底层结构,我们将main.m文件转化为C++的源码、我们打开命令行。cd到包含main.m文件的文件夹,然后输入:

Block在iOS开发中的用途非常广,今天我们就来一起探索一下Block的底层结构。

1. Block的底层结构

下面是一个没有参数和返回值的简单的Block:

int main(int argc, char * argv[]) {    @autoreleasepool {        
        void (^block)(void) = ^{
            
            NSLog(@"Hello World!");
        };
        
        block();        
        return 0;
    }
}

为了探索Block的底层结构,我们将main.m文件转化为C++的源码、我们打开命令行。cd到包含main.m文件的文件夹,然后输入: clang -rewrite-objc main.m ,这个时候在该文件夹的目录下会生成main.cpp文件。

这个文件非常长,我们直接拉到文件的最下面,找到main函数:

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

这第一行代码是定义一个block变量,第二行代码是调用block。这两行代码看起来非常复杂。但是我们可以去简化一下,怎么简化呢?

变量前面的()一般是做强制类型转换的,比如在调用block这一行, block 前面有一个()是(__block_impl *),这就是进行了一个强制类型转换,将其转换为一个 _block_impl 类型的结构体指针,那像这样的强制类型转换非常妨碍我们理解代码,我们可以暂时将这些强制类型转换去掉,这样可以帮助我们理解代码。

化简后的代码如下:

//定义blockvoid (*block)(void) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);//调用blockblock->FuncPtr(block);

这样化简后的代码就要清爽多了。我们一句一句的看,先看第一句:

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

这句代码的意思好像就是调用 _main_block_impl_0 这个函数,给这个函数传进两个参数 _main_block_func_0&_main_block_desc_0_DATA ,然后得到这个函数的返回值,取函数返回值的地址,赋值给block这个指针。

我们在稍微上一点的位置可以找到 _main_block_impl_0 这个结构:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;//构造函数,类似于OC的init方法
  __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这个结构体的结构我们可以command+f在main.cpp文件中搜索得到:

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

_main_block_desc_0结构体的结构在main.cpp文件的最下面可以找到:

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

这是一个C++的结构体。而且在这个结构体内还包含一个函数,这个函数的函数名和结构体名称一致,这在 C语言 中是没有的,这是C++特有的。

在C++的结构体包含的函数称为结构体的构造函数,它就相当于是OC中的init方法,用来初始化结构体。OC中的init方法返回的是对象本身,C++的结构体中的构造方法返回的也是结构体对象。

那么我们就知道了, __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA); 返回的就是 _main_block_impl_0 这个结构体对象,然后取结构体对象的地址赋值给block指针。换句话说,block指向的就是初始化后的 _main_block_impl_0 结构体对象。

我们再看一下初始化 _main_block_impl_0 结构体传进去的参数:

  • 第一个参数是 _main_block_func_0 ,这个参数的结构在上面一点的位置也能找到:

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {  NSLog((NSString *)&__NSConstantStringImpl__var_folders_74_wk04zv690mz36wn0g18r5nxm0000gn_T_main_3b803f_mi_0);
 }

这个函数其实就是把我们Block中要执行的代码封装到这个函数内部了。我们可以看到这个函数内部就一行代码,就是一个NSlog函数,这也就是 NSLog(@"Hello World!"); 这句代码。

把这个函数指针传给 _main_block_impl_0 的构造函数的第一个参数,然后用这个函数指针去初始化 _main_block_impl_0 这个结构体的第一个成员变量 impl 的成员变量 FuncPtr 。也就是说 FuncPtr 这个指针指向 _main_block_func_0 这个函数。

  • 第二个参数是 &_main_block_desc_0_DATA

    我们看一下这个结构:

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

在结构体的构造函数中,0赋值给了reserved, sizeof(struct __main_block_impl_0) 是赋值给了Block_size,可以看出这个结构体存放的是 _main_block_impl_0 这个结构体的信息。在 _main_block_impl_0 的构造函数中我们可以看到, _main_block_desc_0 这个结构体的地址被赋值给了 _main_block_impl_0 的第二个成员变量 Desc 这个结构体指针。也就是说Desc这个结构体指针指向 _main_block_desc_0_DATA 这个结构体。

那么我们总结一下:


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

我是90后,我是创业家

我是90后,我是创业家

腾讯互联网与社会研究院 / 华章图书 / 2015-1-1 / 48.00元

第1本揭秘17个90后精彩创业故事 他们是:脸萌创始人郭列、北大硕士卖米粉的张天一、微博《我只过1%的生活》短时间转发35万多次的伟大的安妮、备受争议的90后总裁余佳文、节操姐CEO陈桦……17位90后的创业家为你分享他们的创业故事!从这些90后孩子的经历中,还可以看到互联网带来的巨大好处,这又是这一代人的幸运。这些创业者有一个共同特点,即他们在做自己事业的时候,会经常遇到来自家庭和社会的阻......一起来看看 《我是90后,我是创业家》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试