OC对象 - Block 的本质
block - 代码块,开发中常用来封装一段代码,在想要执行的时候再调用执行,也常用来做传值、事件传递等等,是不可或缺的一个特性。但是如果使用不当,容易造成循环引用等问题。那block底层到底是怎么实现的呢
1. block的本质
- block本质其实是个OC对象,他内部也有isa指针
- block是封装了函数调用以及函数调用环境的OC对象
- block的底层结构是:

我们把block转成c++代码,来验证下它的底层结构
1.1 查看block底层实现
- 写一个最基础的block
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^{
printf("block~~~\n");
};
block();
}
return 0;
}
- 转成c++代码


struct __block_impl impl对应的就是 block 的底层结构

1.1.1 初始化block
- 刚刚声明的 block
void(^block)(void) = ^{
printf("block~~~\n");
};
实际上它转成了
// 定义 block 变量。传入的两个参数,对应赋值给 impl.FuncPtr 和 Desc
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
他是初始化了一个__main_block_impl_0结构体,

__main_block_impl_0构造方法接收两个参数void *fp和struct __main_block_desc_0 *desc,可以看到此处代码传入的值是(void *)__main_block_func_0和&__main_block_desc_0_DATA
这两个参数传进__main_block_impl_0后赋值给了 impl.FuncPtr和Desc
(void *)__main_block_func_0对应的是:

其实就是把我们 block 里面所写的代码封装成函数传进去。
Desc则是block的描述信息,对应结构体__main_block_desc_0

reserved仅是个保留字段,Block_size则表示 block 的大小
1.1.2 调用block
我们初始化block后,通过block()调用了block
底层对应转成这样:
// 执行 block 的内部函数,可简化为:block->FuncPtr(block)
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
他实际上就是帮我们调用了刚刚初始化时传入的保存在impl.FuncPtr的函数
此时block里面的代码就被调用执行了
@oubijiexi
本文详细探讨了Objective-C中Block的本质,揭示其作为OC对象的底层结构,包括初始化过程中的__block_impl和__block_func,以及如何通过isa指针和调用函数来执行。还讨论了正确使用Block以避免循环引用问题。
1485

被折叠的 条评论
为什么被折叠?



