返回

Block(下)- 底层源码分析

IOS

前言

在前一篇文章中,我们学习了Block的三种表现形式,了解了引用计数和循环引用的相关知识。在这篇文章中,我们将进一步深入探讨Block的底层实现,探究其内部结构、copy机制和循环引用处理。通过对Block底层原理的剖析,帮助读者更好地理解Block的运行机制和内存管理细节,以便在实际开发中更加熟练地使用Block。

Block的底层结构

Block在底层是由C语言实现的,其本质上是一个函数指针,指向一个由编译器生成的函数。这个函数包含了Block的实现代码,以及对捕获变量的引用。Block的结构如下:

struct Block_layout {
    void *isa; // 指向Block的类型信息
    int flags; // Block的标志位,用于标记Block的属性
    int reserved; // 保留字段
    void (*invoke)(void *, ...); // 指向Block实现代码的函数指针
    struct Block_descriptor *descriptor; // 指向Block符的指针
};
  • isa:指向Block的类型信息,用于确定Block的类型。
  • flags:Block的标志位,用于标记Block的属性,如是否可复制、是否可捕获变量等。
  • reserved:保留字段,用于将来扩展使用。
  • invoke:指向Block实现代码的函数指针,当Block被调用时,会跳转到这个函数执行。
  • descriptor:指向Block符的指针,Block描述符包含了Block捕获变量的信息。

Block的Copy机制

Block是可复制的,这意味着可以创建Block的副本,副本与原Block具有相同的功能。Block的copy机制是通过创建一个新的Block结构体来实现的,新的Block结构体包含了与原Block相同的函数指针和Block描述符,但捕获变量的引用会被复制一份。

Block的copy过程如下:

  1. 分配内存空间来存储新的Block结构体。
  2. 将原Block的函数指针和Block描述符复制到新的Block结构体中。
  3. 将原Block捕获变量的引用复制到新的Block结构体中。
  4. 将新的Block结构体的地址返回给调用者。

Block的循环引用处理

Block可以捕获变量,这可能会导致循环引用。循环引用是指两个或多个对象相互引用,导致内存无法被释放。为了防止循环引用,Block在底层实现了循环引用检测和处理机制。

Block的循环引用检测机制如下:

  1. 当Block被创建时,会将Block描述符添加到一个全局的循环引用检测表中。
  2. 当Block被释放时,会从循环引用检测表中删除Block描述符。
  3. 当循环引用检测表中只剩下一个Block描述符时,说明该Block及其捕获变量已经成为循环引用,此时会触发循环引用处理机制。

Block的循环引用处理机制如下:

  1. 将Block描述符从循环引用检测表中删除。
  2. 释放Block捕获变量的内存空间。
  3. 释放Block结构体的内存空间。

结语

通过对Block底层源码的分析,我们深入了解了Block的内部结构、copy机制和循环引用处理。这些知识对于我们理解Block的运行机制和内存管理细节非常重要,有助于我们在实际开发中更加熟练地使用Block。