2015技术笔记

2015笔记——Block探究

2018-07-27  本文已影响3人  满庭花醉三千客

自己根据步骤进行了Block的实现的本质探究:

(一)

首先来看最简单的仅仅打印一句话的block:

屏幕快照 2015-11-24 09.36.06.png

转为C++的部分文件为:

block的实现.png

从第一个结构体的命名可以看出这是block的实现,并且得知block在Clang编译器前端得到实现,可以生成C中间代码。

屏幕快照 2015-11-24 09.35.43.png

第一部分:

block的实现结构体: 1、block的实现

                                2、block的描述信息结构体

                                3、block的构造函数

block的构造函数中:包含了初始化block的类型、初始化block的函数指针。

注:NSConcreteStackBlock意为block位于栈中。

第二部分:

block的函数体:接收一个__cself的参数,即对应的block自身。

第三部分:

block的描述信息结构体:含有block的大小

第四部分:

main函数:block的创建和调用。

创建:将block的函数体和block的描述信息传给构造函数。

调用:就是调用一个以block自身作为参数的函数,该函数为block的函数体。

在将block作为回调函数传递给底层框架时,底层框架需要对其copy一份。我们通常将block写在栈中,需要回调时,往往回调block已经不在栈中了,使用copy属性可以将block放在堆中。

(二)

带有变量的block的实现:

B.png

转为C++ 之后的部分文件为:

B cc.png

第一部分:多了一个成员变量int型i,用来存储使用到的局部变量i。构造函数中,多了一个表达式 i(_i),这是一个赋值的过程。

第二部分:从此处可以看出,__cself参数的作用,类似于OC中的self。

第三部分:基本上无变化。

第四部分:在创建block时,多传入一个int型的参数i,值为1024。

因为main函数(第四部分)中的局部变量i和函数__main_block_func_0(第二部分)不在同一个作用域中,调用过程中只是进行了值传递。在上面代码中,我们可以通过指针来实现局部变量的修改,前提是在调用__main_block_func_0时,main函数栈还没展开完成(main函数还未执行完,即block在main函数创建完后,立即调用),变量i还在栈中。但是在很多情况下,block是作为参数传递以供后续回调执行的。通常在这些情况下,block被执行时,定义时所在的函数栈已经被展开,局部变量已经不在栈中了(block此时被copy到堆中),再用指针访问就会崩溃。

(三)

变量前有__block指示符,block的创建和调用:

C.png

转为C++之后的部分文件:

C cc(上).png C cc(下).png

第一部分:

block变量对应的结构体,由第一个成员__isa可知,__Block_byref_i_0也可以是NSObject对象。

第二个成员变量指向自己,但指向自己是没有意义的,所以其有时需要指向另一个__Block_byref_i_0结构。

最后一个变量是目标存储变量i。

第二部分:

__main_block_impl_0的成员变量i变成了__Block_byref_i_0类型的一个变量。

第三部分:

block的函数体中,__Block_byref_i_0指针类型变量i,通过其成员变量__forwarding指针来操作另一个成员变量。

第六部分:

block的描述信息中多了两个成员函数,对应于第四部分和第五部分。

第四部分的功能为:当block从栈上拷贝到堆上时,该函数将__Block_byref_i_0类型的成员变量i从栈上复制到堆上。

第五部分的功能为:当block释放时,该函数释放__Block_byref_i_0类型的成员变量i。

此外,如果栈上和堆上同时对该变量进行操作,则_forwarding的作用就体现出来了:当一个__block变量从栈上被复制到堆上时,栈上的__Block_byref_i_0结构体中的__forwarding指针也会指向堆上的结构。

第七部分:

main中先构建了一个__Block_byref_i_0型的i,并设置了__forwarding -> &i 以及i的初始值1024。

构建myBlock时,向构造函数中传入了函数体,描述信息,&i。

总的概括:

带有__Block 指示符的变量i,block中会多出一个结构体,该结构体中有一个_forwarding指针,通过该指针可以操作成员变量i。而且当一个栈上的__Block_byref_i_0变量复制到了堆上,则栈上的__Block_byref_i_0结构体中的_forwarding指针会指向堆上的结构。

此外,block的描述结构体中多出两个成员函数,当block发生拷贝和释放时,对__block类型的成员变量i进行拷贝与释放。

附图一张:

屏幕快照 2015-11-24 11.47.16.png

加油~

上一篇 下一篇

猜你喜欢

热点阅读