Block的本质
我们将block代码编译成cpp文件
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^{
};
block();
}
return 0;
}
// clang main.m -rewrite-objc -o main.cpp 生成的cpp文件代码很多,直接拉到底部
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) {
}
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, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
我们整理一下,可以得出block的底层数据结构
struct __block_impl
{
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
通过上面,我们可以看出block的本质也是一个OC对象,有一个isa指针,FuncPtr表示执行代码块的函数地址
block捕获
- 全局变量
- 全局静态变量
- 局部变量
- 静态局部变量
将上面代码转成cpp
通过截图我们也就明白,局部变量,直接拷贝一份
(看截图参数 int _y)也就是我们说的捕获,静态局部变量是指针传递(看截图参数 * _z),我们得出如下结论
__block
我们知道如果想要在block内部修改局部变量的值,这个局部变量需要用__block修饰,
接下来我们探索一下__block到底做了哪些事情
同样将上面代码转成cpp代码
- __isa指针
- __forwarding我理解为传入变量的地址
- y 变量的值 这样我们就可以知道 __block修饰的变量 在block内为什么可以被修改