block数据结构
写下如下代码,然后在终端进入.m文件所在目录,执行命令xcrun -sdkiphoneos clang -arch arm64 -rewrite-objc ArcClass.m 我们可以看到在当前目录生成ArcClass.cpp文件
int age = 18;
void (^block)(void) = ^{
NSLog(@"age is %d",age);
};
block();
我们可以看到上面的代码变成了
int age = 18;
// block定义
void (*block)(void) = ((void (*)())&__ArcClass__TestArc_block_impl_0((void *)__ArcClass__TestArc_block_func_0,&__ArcClass__TestArc_block_desc_0_DATA, age));
// block调用
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
上面代码删除掉一些强制转换的代码简化如下
int age = 18;
// block定义
void (*block)(void) = & __ArcClass__TestArc_block_impl_0(
&__ArcClass__TestArc_block_func_0,
& __ArcClass__TestArc_block_desc_0_DATA,
age
);
// block调用
block->FuncPtr(block);
我们可以看到block是指向__ArcClass__TestArc_block_impl_0对象的指针,结构体__ArcClass__TestArc_block_impl_0定义如下:
struct __ArcClass__TestArc_block_impl_0 {
struct __block_impl impl;
struct __ArcClass__TestArc_block_desc_0*Desc;
int age;
__ArcClass__TestArc_block_impl_0(void *fp,struct __ArcClass__TestArc_block_desc_0 *desc,int _age,int flags=0): age(_age) {
impl.isa =&_NSConcreteStackBlock;
impl.Flags= flags;
impl.FuncPtr= fp;
Desc = desc;
}
};
该结构体把age直接赋值给了_age,执行的是拷贝操作。
- 结构体中第一个成员变量是struct __block_impl impl;
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
}
__block_impl 的成员变量isa代表了该block属于啥类型,本例中为_NSConcreteStackBlock,FuncPtr代表block的调用方法,本例中为__ArcClass__TestArc_block_func_0
- 第二个成员变量是struct __ArcClass__TestArc_block_desc_0* Desc;
static struct __ArcClass__TestArc_block_desc_0 {
size_t reserved;
size_t Block_size;
}__ArcClass__TestArc_block_desc_0_DATA= { 0, sizeof(struct__ArcClass__TestArc_block_impl_0)};
desc描述了__ArcClass__TestArc_block_impl_0的大小
-
结构体中第三个是成员变量age
该结构体把age直接赋值给了_age,执行的是拷贝操作。 -
block调用实际上执行的是__ArcClass__TestArc_block_func_0方法
下面为 block方法代码NSLog(@"age is %d",age);的实现
static void __ArcClass__TestArc_block_func_0(struct __ArcClass__TestArc_block_impl_0 *__cself) {
//这里访问age是bound by copy ,即拷贝。
int age = __cself->age; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_x0_cw796jjd255431nlsdwjt9840000gn_T_ArcClass_6c36ef_mi_0,age);}
从上面的分析可以看到,定义一个block的时候,底层生成了一个代表block的结构体__ArcClass__TestArc_block_impl_0,该结构体有一个__block_impl类型的impl成员变量和代表捕获变量的成员变量。其中impl的isa 代表了block的类型,FuncPtr代表了block的实际调用方法,该方法的参数为__ArcClass__TestArc_block_impl_0。
网友评论