《Objective-C高级编程》读书笔记--2.3.1--Blocks的实质
栏目: Objective-C · 发布时间: 5年前
内容简介:Blocks的原理,每当自己对知识体系有一定提升之后,再回过头来看一下曾经读过的书籍,会发现对它的理解逐步加深。借着读书笔记活动,立个小目标,把Block彻底搞明白,重读《Objective-C高级编程 iOS与OS X多线程和内存管理》第二章节block原理部分,一方面给自己做个笔记,另一方面加深以下印象。block代码:执行
Blocks的原理,每当自己对知识体系有一定提升之后,再回过头来看一下曾经读过的书籍,会发现对它的理解逐步加深。借着读书笔记活动,立个小目标,把Block彻底搞明白,重读《Objective-C高级编程 iOS与OS X多线程和内存管理》第二章节block原理部分,一方面给自己做个笔记,另一方面加深以下印象。
block实质
block代码:
void (^blk)(void) = ^ { printf("Block"); }; blk(); 复制代码
执行 xcrun -sdk iphonesimulator clang -rewrite-objc 源代码文件名
就能将含有Block的代码转换为C++的源代码。我是按照书上的示例,同样转换的main.m文件,转换完之后这里就会多出一个 main.cpp
的文件,打开很恐怖, 六万多行...
实际上和block相关的代码在最后几十行:
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; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { printf("Block"); } 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)}; int main(int argc, char * argv[]) { void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk); return 0; } 复制代码
这就是我们一直在使用的block,因为都是struct结构看上去有点抽象,不过理解起来并不难。
首先先从 __main_block_func_0
函数开始,因为我们想要执行的回调看源码都是写在这个函数里面的,block使用的匿名函数(也就是我们定义的block)实际上被作为简单的 C语言 函数( block__main_block_func_0
)来处理,该函数的参数__cself相当于OC实例方法中指向对象自身的变量self,即__self为指向Block值的变量。__self与OC里面的self相同也是一个结构体指针,是 __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; } }; 复制代码
第一个变量是 impl
,也是一个结构体,声明如下:
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }; 复制代码
先看 FuncPrt
,这个就是 block
括号中函数的函数指针,调用它就能执行block括号中的函数,实际上在调用block的时候就是调用的这个函数指针,执行它指向的具体函数实现。 第二个成员变量是 Desc
指针,以下为其 __main_block_desc_0
结构体声明:
static struct __main_block_desc_0 { size_t reserved; size_t Block_size; } 复制代码
其结构为今后版本升级所需的区域和Block的大小。 实际上 __main_block_impl_0
结构体展开最后就是这样:
struct __main_block_impl_0 { void *isa; int Flags; int Reserved; void *FuncPtr; 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
结构体所包含的,既然定义了这个结构体的初始化函数,那在详细看一下它的初始化过程,实际上该结构体会像下面这样初始化:
isa = &_NSConcreteStackBlock; Flags = 0; Reserved = 0; FuncPtr = __main_block_func_0; Desc = &__main_block_desc_0_DATA; 复制代码
__main_block_func_0
这不就是上面说到的那个指向函数实现的那个函数指针,也就是说只需要调用到结构体里面的 FuncPtr
就能调用到我们的具体实现了。那这个构造函数在哪里初始化的,看上面的源码是在我们定义block的时候:
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); 复制代码
简化为:
struct __mian_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA); struct __main_block_impl_0 *blk = &tmp; 复制代码
该源代码将 __mian_block_impl_0
结构体类型的自动变量,即栈上生成的 __mian_block_impl_0
结构体实例的指针,赋值给 __mian_block_impl_0
结构体指针类型的变量blk。听起来有点绕,实际上就是我们最开始定义的 blk
为 __main_block_impl_0
结构体指针指向了 __main_block_impl_0
结构体的实例。
接下来看看 __main_block_impl_0
结构体实例的构造参数:
__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA); 复制代码
第一个参数为由Block语法转换的C语言函数指针,第二个参数是作为静态全局变量初始化的 __main_block_desc_0
结构体实例指针,以下为 __main_block_desc_0
结构体实例的初始化部分代码:
static struct __main_block_desc_0 __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0) }; 复制代码
即 __main_block_impl_0
结构体实例的大小。
接下来看看栈上的 __main_block_impl_0
结构体实例( 即Block
)是如何根据这些参数进行初始化的。也就是 blk()
的具体实现:
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk); 复制代码
简化以下:
(*blk->impl.FuncPtr)(blk); 复制代码
FuncPtr
正是我们初始化 __main_block_desc_0
结构体实例时候传进去的函数指针,这里使用这个函数指针调用了这个函数,正如我们刚才所说的,有block语法转换的__ main_block_func_0
函数的指针被赋值成员变量 FuncPtr
中。 blk
也是作为参数进行传递的,也就是最开始讲到的 __cself
。到此 block
的初始化和调用过程就结束了。
待更新...
以上所述就是小编给大家介绍的《《Objective-C高级编程》读书笔记--2.3.1--Blocks的实质》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
谷歌时代的柏拉图
[美] 丽贝卡·戈尔茨坦 / 李鹏程 / 中信出版集团·新思文化 / 2017-12-10 / 69.00元
我愿意用我所有的科技去换取和苏格拉底相处的一个下午。 ——史蒂夫•乔布斯 谷歌时代,科技昌明,众声喧哗,哲学提出的许多问题,科学似乎都已经给出了答案。若是如此,为什么我们今天还需要哲学?这个由古希腊城邦时代的哲人苏格拉底和柏拉图开创的学科,真的过时了吗? 已经2400岁 的柏拉图对此有话要说。哲学家兼小说家、美国国家人文奖章获得者戈尔茨坦史海钩沉,从经典著作中复活了柏拉图,让他来......一起来看看 《谷歌时代的柏拉图》 这本书的介绍吧!
Base64 编码/解码
Base64 编码/解码
URL 编码/解码
URL 编码/解码