因为Block语法可以截获自动变量的值,因为在实现上不能修改被截获自动变量的值(因为在block初始化时,自动变量的值保存在block的结构体实例中),所以修改被截获自动变量的值会报编译错误
如果我们要修改Block中的值,或者说在Block中保存值;有两种解决方法
(1)C语言中的静态变量、静态全局变量、全局变量,允许Block修改值
(2)使用__block修饰符,带有__block的变量,允许Block修改值
下面来具体解释原因
(1)C语言中的静态变量、静态全局变量、全局变量,允许Block修改值
int global_val = 1;
static int stativ_global_val = 2;
int main(int argc, const char * argv[]) {
static int static_val = 3;
void (^blk)(void) = ^{
global_val *= 1;
stativ_global_val *= 2;
static_val *=3;
};
return 0;
}
分析源码
int global_val = 1;
static int stativ_global_val = 2;
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *static_val;//局部的静态变量出现在__main_block_impl_0结构体中
//构造函数中传入static_val的信息
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int *static_val = __cself->static_val; // bound by copy
//静态全局变量和全局变量的访问变换前后没变化
global_val *= 1;
stativ_global_val *= 2;
(*static_val) *=3;
printf("%d,%d,%d",global_val,stativ_global_val,(*static_val));
}
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[]) {
static int static_val = 3;
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
return 0;
}
分析:
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int *static_val = __cself->static_val; // bound by copy
//静态全局变量和全局变量的访问变换前后没变化
global_val *= 1;
stativ_global_val *= 2;
(*static_val) *=3;
printf("%d,%d,%d",global_val,stativ_global_val,(*static_val));
}
由源码看出对静态变量的访问转变为(*static_val) *=3;
使用static_val指针访问静态变量,将静态变量static_val的指针放在__main_block_impl_0结构体的构造函数保存。这是超出作用域使用变量的简单方法。
(2)使用__block修饰符,带有__block的变量,允许Block修改值
int main(int argc, const char * argv[]) {
__block int val = 10;
void (^blk)(void) = ^{ val = 1;};
return 0;
}
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;
// __main_block_impl_0持有指向__Block_byref_val_0实例的指针
__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; // bound by ref
(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((void*)&dst->val, (void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);
}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t 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(int argc, const char * argv[]) {
__attribute__((__blocks__(byref))) __Block_byref_val_0 val =
{ (void*)0,
(__Block_byref_val_0 *)&val,
0,
sizeof(__Block_byref_val_0),
10
};
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_0 *)&val, 570425344));
return 0;
}
分析:
(1)在自动变量前加__block修饰符,__block int val = 10;
会在源代码中转变为如下结构体实例
__attribute__((__blocks__(byref))) __Block_byref_val_0 val =
{ (void*)0,
(__Block_byref_val_0 *)&val,
0,
sizeof(__Block_byref_val_0),
10
};
即__block变量变成了__Block_byref_val_0结构体类型的自动变量,即栈上生成__Block_byref_val_0结构体实例。
struct __Block_byref_val_0 {
void *__isa;
__Block_byref_val_0 *__forwarding;//持有指向结构体实例的指针
int __flags;
int __size;
int val;//val也出现在结构体中作为成员变量
};
(2)^{ val = 1;};
转换成下面代码
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself->val; // bound by ref
(val->__forwarding->val) = 1;
}
cself是指向__main_block_impl_0 结构体的指针,__main_block_impl_0结构体中增加了一项,即__Block_byref_val_0 *val;也就是__main_block_impl_0结构体的实例持有指向__Block_byref_val_0结构体实例的指针。
__Block_byref_val_0结构体实例的成员变量__forwarding持有指向该实例自身的指针。通过__forwarding访问变量val。·