Block底层实现之逆向思维

前段时间心血来潮,研究了一下block底层实现,在网上看了好多文章,基本都是通过clang 将代码转换为C++代码去分析Blcok的实现。今天我们反过来思考,用C去实现一个OC Block的效果。

Block的实现本质上是一些结构体,函数指针,函数,的综合运用。

话不多说,直奔主题:

Block的实现,首先需要声明一个结构,这个结构是我们实现Block的基础,也是关键

1
2
3
4
5
6
7
8
9
10
11
struct __block_impl {

void *isa;

int Flags;

int Reserved;

void *FuncPtr;

};

说明一下:

1.isa 保存的是Block的类型

2.Flags 当block发生copy时,会用到

3.FuncPtr 指针,指向block内的函数实现(后面函数指针调用的函数)

这个结构体,是所有类型的Block都会有的一部分。

然后我们看第二个结构体

1
2
3
4
5
6
7
static struct __simpleblk_block_desc_0 {

size_t reserved;

size_t Block_size;

} __simpleblk_block_desc_0_DATA = {0,sizeof(struct __simpleblk_block_impl_0)};

说明一下:

1.reserved 保留字段默认是0

2.Block_size 用来保存block所占内存大小。

这个结构体用来描述block的大小等信息,simpleblk_block_desc_0_DATA是simpleblk_block_desc_0的一个结构体实例。

我们再看第三个结构体,也是Block实现最重要的结构,声明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct __simpleblk_block_impl_0 {

struct __block_impl impl;

struct __simpleblk_block_desc_0 *Desc;

__simpleblk_block_impl_0(void *fp,struct __simpleblk_block_desc_0 *desc,int flags = 0){

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

说明一下:

从这个结构中可以看到,该结构体含有 block_impl 结构的变量 和 simpleblk_block_desc_0 结构的变量,以及结构体构造函数simpleblk_block_impl_0,结构体构造函数用来初始化变量block_impl和__simpleblk_block_desc_0。

到这里,我们实现最简单的Block所需要的结构就声明完了,但是要达到OC Block 那种效果,仅有结构体 肯定是不够的。截下来我们来看一个关键的函数,你没猜错就是一个很简单的C函数:

1
2
3
4
5
static void __simpleblk_block_func_0(struct __simpleblk_block_impl_0 *__cself) {

printf("this is charles's simple block!!");

}

这个函数其实就是我们的Block块里面的操作。后面调用之后就会很清楚。

到这里我们就可以写一个C函数来达到一个Block的效果:

int simpleblk(){

//声明一个结构体变量

1
__simpleblk_block_impl_0 __simpleblk_impl0 = __simpleblk_block_impl_0((void *)__simpleblk_block_func_0,&__simpleblk_block_desc_0_DATA);

//声明一个函数指针变量block,并且将上面的结构体变量的地址付给block指针

1
void(*block)(void) = (void(*)())&__simpleblk_impl0;

1
2
3
4
/*
下面这句代码 实际上调用的是 __simpleblk_block_func_0()函数
就是函数指针调用函数。
*/
1
2
3
4
5
((void (*)(struct __block_impl *))((struct __block_impl *)block)->FuncPtr)((struct __block_impl *)block);

return 1;

}

其实,上面写了这么多,换成OC代码其实就是在一个函数里面,声明了一个Block变量并且调用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
int simpleblk() {

void (^block)(void) = ^(){

printf("this is charles's block!!");

};

block();

return 1;

}

到这里我们用C语言实现OC的 Block效果基本就写完了,不知道各位看官是否看明白了呢。。(PS:欢迎大家勘误,共同学习!)

谢谢您的支持!