《Objective-C高级编程》读书笔记--2.3.1--Blocks的实质

栏目: Objective-C · 发布时间: 7年前

内容简介: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 的文件,打开很恐怖, 六万多行...

《Objective-C高级编程》读书笔记--2.3.1--Blocks的实质

实际上和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的实质》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

機器,平台,群眾

機器,平台,群眾

安德魯‧麥克費(Andrew McAfee)、艾瑞克‧布林優夫森(Erik Brynjolfsson) / 李芳齡 / 天下文化 / 2017-12-27 / TWD550

★★Amazon.com商業理財Top1 ★★ 全球暢銷書《第二次機器時代》作者最新力作 兩位MIT數位頂尖科學家歷時三年時間 走訪矽谷、華府、劍橋、紐約、倫敦、舊金山等科技政經重鎮 拜會許多領域精英進行交流,結合宏觀趨勢觀察, 指出人人都應關注的三重革命 科技正以空前速度改變每個產業及每個人的生活, 你該如何做,才能保持領先? 我們生活在一個奇特的......一起来看看 《機器,平台,群眾》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具