Block中使用__block变量的情况
</br>
Block要修改值的第二种方法:使用__block说明符
,全称为__block存储域类说明符
。C语言中有以下存储域类说明符:
- typedef
- extern
- static
- auto
- register
__block
说明符类似于static
、auto
和register
说明符,它们用于指定将变量值设置到哪个存储域中。例如,auto
表示作为自动变量存储在栈中,static
表示作为静态变量存储在数据区中。以下是分析例子:
Objective-C
__block int val = 10;
void (^blk)(void) = ^{ val = 1; };
C++
struct __Block_byref_val_0 {
void *__isa;
__Block_byref_val_0 *__forwarding;
int __flags;
int __size;
int val;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0 *Desc;
__Block_byref_val_0 *val;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself->val;
(val->__forwarding->val) = 1;
}
static void __main_block_copy_0 (struct __main_block_impl_0 *dst, struct __main_block_impl_0 *src) {
_Block_object_assign(&dst->val, src->val, BLOCK_FIELD_IS_BYREF);
}
static void __main_block_dispose_0(struct __main_block_impl_0 *src) {
_Block_object_dispose(src->val, BLOCK_FIELD_IS_BYREF);
}
static struct __main_block_desc_0 {
unsigned long reserved;
unsigned long Block_size;
void (*copy)(struct __main_block_impl_0 *, struct __main_block_impl_0 *);
void (*dispose)(struct __main_block_impl_0 *);
} __main_block_desc_0_DATA = {
0,
sizeof(struct __main_block_impl_0),
__main_block_copy_0,
__main_block_dispose_0
};
int main() {
__Block_byref_val_0 val = {
0,
&val,
0,
sizeof(__Block_byref_val_0),
10
};
blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);
return 0;
}
新增的部分以粉红色显示。
从图中看到,__block变量
被转换为_Block_byref_val_0
结构体,Block的成员变量有一个指向该结构体的指针。Block成员变量保留指针而不是一个结构体的设计,是为了能够在多个Block使用__block变量
。下面是说明这个问题的例子。
__block int val = 10;
void (^blk0)(void) = ^{ val = 0;};
void (^blk1)(void) = ^{ val = 1;};
__Block_byref_val_0 val = {
0,
&val,
0,
sizeof(__Block_byref_val_0),
10
};
blk0 = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x22000000);
blk1 = &__main_block_impl_1(__main_block_func_1, &__main_block_desc_1_DATA, &val, 0x22000000);
两个Block都使用了__Block_byref_val_0
结构体实例val
的指针。这样一来就可以从多个Block中使用同一个__block变量
。当然,反过来从一个Block中使用多个__block变量
也没有问题。只要增加Block的结构体成员变量与构造函数的参数,便可对应使用多个__block变量
。
Block数据结构图(6)中Desc
新增的两个函数指针,copy函数用于�复制Block,dispose函数用于废弃Block。
上例的int型__block变量转换成结构体之后,有一个void *__isa
指针的成员变量,这说明我们也可以把它看作实例。