1. 界说

网上有各种关于闭包的界说,个人觉得比较严谨的界说是:

  1. 在一个函数内部,另一个函数和它所捕获的变量\常量环境组合起来,整体称为闭包。
  • 一般界说在函数内部的函数。
  • 一般捕获的是外层函数的局部变量\常量。

Swift 闭包底层原理

2. 猜想

Swift的闭包,其实质会不会跟OC的闭包相同,也是一个目标呢?

如果能够证明一起满意以下两点,那么就能够证明,闭包的实质,便是一个目标:

  1. 拓荒了堆空间。
  2. 而且它的内存结构跟class相同。

3. 证明拓荒了堆空间

如果调了alloc,最终调了malloc函数,那么就阐明向堆空间请求了内存。

1. 打断点,看函数getNumber内部是怎么实现的。

Swift 闭包底层原理

2. 进入汇编,持续进入getNumber函数。

Swift 闭包底层原理

Swift 闭包底层原理

3. 持续进入swift_allocObject函数。

Swift 闭包底层原理

4. 持续进入swift_showAlloc函数,能够看出,的确调了malloc_zone_malloc函数,那由此能够证明,的确在堆区拓荒了空间。

Swift 闭包底层原理

4. 证明闭包的内存结构跟类相同

要想证明闭包的内存结构跟类相同,那就需要先找出刚创建好的目标,然后打印出它的内存地址,然后查看内存地址中存储着什么,然后跟类的内存结构对比,然后判别出闭包的内存结构。

1. 依旧是这份代码,打开反汇编。

Swift 闭包底层原理

2. 第6行,注释写的很清楚,调用getNumber函数,持续跟进去。

Swift 闭包底层原理

3. 发现这个函数 swift_allocObject 刚分配完空间,那是不是刚请求完堆空间的闭包,打印相同返回值 rax。

Swift 闭包底层原理

4. 打印rax的内存地址,并打印出这个内存地址的内存结构。

前8个字节存储着类型信息,然后引证计数,然后成员变量。

内存结构跟class一模相同。

Swift 闭包底层原理

由此能够判别出,闭包的实质便是一个可实例的目标。

用法是不是跟类的实例目标很像很像。

Swift 闭包底层原理

5. 总结

其实Swift的闭包跟OC的Block,其实质是差不多的。

从汇编能够看出,闭包捕获局部变量,是调用了malloc函数, 拓荒了堆空间,调用malloc所拓荒出来的空间,打印其内存地址,窥探它的内存结构,发现是类的内存结构,就足以阐明闭包的实质,是一个目标。

第一条是类信息,第二条存储的是引证计数,第三条是存储的局部变量的地址。

在函数内的函数,捕获了外部函数的局部变量,将外部函数的局部变量从栈空间copy到堆空间,封装成目标,并进行内存管理。