上一节分析了Block截获int
, char*
类型自动变量的源码, 发现Block内部用成员变量的形式保存了被截获的自动变量的值, 因此直接在Block内部修改值, 外部的自动变量的值并不会修改, 因此, 要修改变量的值, 我们使用以下三种变量应该可以:
- 静态全局变量
- 静态局部变量
- 全局变量
int global_val = 1;
static int static_global_val = 2;
int main() {
static int static_val = 3;
void (^blk)() = ^ {
global_val *= 1;
static_global_val *= 2;
static_val *= 3;
}
return 0;
}
此时以下部分发生改变:
int global_val = 1;
static int static_global_val = 2;
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *static_val; // 需要内部存储静态局部变量的地址.
//构造函数中需要传入 `*_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;
}
};
//3. 成员函数, 在执行时, 是的是Block变量的成员变量
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
// 静态局部变量,获取静态局部变量的地址,
int *static_val = __cself->static_val;
global_val *= 1; // 全局变量, 可以直接使用
static_global_val *= 2; // 静态全局变量, 可以直接使用
(*static_val) *= 3; // 静态局部变量,通过地址设置值
}
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(){
static int static_val = 3;
//创建Block变量时, 需要传入static_val的地址. 在Block结构体内部, 通过指针保存静态局部变量的地址,用来完成
void (*blk)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));
return 0;
}
结论:
使用全局变量/静态全局变量时, Block是没有对这两类变量进行特殊处理的, 直接在FunPtr中进行修改. 而使用静态局部变量时, 在Block结构体内部用一个成员指针去指向捕获静态局部变量的地址, 在Block执行时, 直接从捕获的地址中修改该静态局部变量的值.
参考资料
- <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>
- https://blog.csdn.net/deft_mkjing/article/details/53149629