返回
OC底层:揭秘Block本质(一、原理)
IOS
2023-10-27 10:24:39
在Objective-C中,Block是一种非常实用的特性,它允许开发者将代码块作为参数传递给其他函数或方法,从而实现代码的重用性和灵活性。那么,Block在底层是如何实现的呢?本文将从Block的定义入手,逐层探索Block的本质,揭示其内部结构和工作机制,并探讨Block与内存管理、运行时的紧密联系,帮助读者全面理解Block的强大之处。
## Block的定义
typedef struct _NSConcreteGlobalBlock {
void *__isa_NSConcreteGlobalBlock;
int __flags;
int __reserved;
void *invoke;
struct Block_layout *__block_impl;
} *NSConcreteGlobalBlock;
从Block的定义中,我们可以看到Block本质上是一个结构体,其中包含了指向isa指针、标志位、预留位、调用函数的指针和Block布局指针等成员。
## Block的内部结构
Block的内部结构由Block_layout结构体定义,如下:
typedef struct Block_layout {
void __isa_NSBlock_layout;
int __flags;
int __size;
void (__invokingFunctionPointer)(void *);
void *__descriptor;
void *__forwarding;
void *__signature;
void reserved;
void (__invokingBlockInvokeFunctionPointer)(void *);
const char *__blockDescription;
//省略其他成员...
} Block_layout;
Block_layout结构体中包含了许多重要的成员,包括指向isa指针、标志位、Block大小、调用函数的指针、符、转发指针、签名、预留位、调用Block的调用函数指针和Block的字符串等。这些成员共同构成了Block的内部结构,定义了Block的行为和属性。
## Block的工作机制
当创建一个Block时,编译器会为Block生成一个Block_layout结构体,并将Block的代码编译成一个函数。这个函数被称为Block的调用函数。调用函数的地址被存储在Block_layout结构体的__invokingFunctionPointer成员中。
当执行Block时,实际上是调用了Block的调用函数。调用函数会根据Block_layout结构体中的信息,确定Block的签名、参数列表和返回值类型,并执行Block的代码。
## Block与内存管理
Block在内存中是以堆分配的方式存储的。当创建一个Block时,编译器会为Block分配一块内存空间,并将Block的调用函数的地址和Block_layout结构体的内容复制到这块内存空间中。
Block的内存空间在Block执行完成后会被释放。但是,如果Block被捕获,那么Block的内存空间不会被释放,而是会被保留到捕获它的作用域结束时才释放。
## Block与运行时
Block与运行时紧密相关。当执行一个Block时,运行时会根据Block_layout结构体中的信息,查找Block的调用函数并执行它。运行时还负责管理Block的内存空间,并在Block执行完成后释放它。
## 结语
Block是Objective-C中非常实用的特性,它允许开发者将代码块作为参数传递给其他函数或方法,从而实现代码的重用性和灵活性。Block的底层实现非常复杂,涉及到内存管理、运行时等多个方面。但通过本文的剖析,我们已经对Block的本质和工作机制有了深入的了解。