iOS Block学习笔记(四) -- Block截获自动变量的
2018-11-23 本文已影响15人
brownfeng
前面, 我们知道Block本质是一个结构体, 当Block内部使用Block外部定义的自动变量, Block会截获这个自动变量的, 那么底层是如何实现的呢, 有如下源码:
int main() {
int a = 100;
int b = 200;
const char *ch = "b = %d\n";
void (^blk)(void) = ^{
printf(ch,b);
};
b = 300;
ch = "value had changed. b = %d\n";
blk();
return 0;
}
// 结果打印: b = 200;
转换成c++代码以后, 如下:
//1. Block "基类"
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
//2. 实际的Block的特定的Block"类", 继承自"__block_impl 基类", 并且注意增加了两个成员变量`const char *ch`, `int b`, 并且构造函数也需要传入这两个成员变量进行初始化.因此Block是通过成员变量来截获自动变量的瞬时值.
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
const char *ch;// 新增成员变量, 用来保存截获的自动变量的值
int b;//新增成员变量, 用来保存截获的自动变量的值
// 构造函数需要传入自动变量, 并且截获自动变量的瞬时值
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_ch, int _b, int flags=0) : ch(_ch), b(_b) {
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) {
// 根据Block内部截获的自动变量的值, 调用具体的Block的方法
const char *ch = __cself->ch; // bound by copy
int b = __cself->b; // bound by copy
printf(ch,b);
}
//4. Block描述
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 a = 100;
int b = 200;
const char *ch = "b = %d\n";
// 创建Block变量, 隐藏步骤: 传入需要被截获的自动变量当做参数, 这里是 ch 和 b. 由于变量a没有在Block中使用, 因此不会被截获.
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, ch, b));
b = 300;
ch = "value had changed.b = %d\n";
// 执行Block函数时, Block实例时, 会使用实例的成员变量, 因此 b, ch的改变并不会影响被截获的值.
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk); // 可以简写成 (*blk)->FuncPtr(blk);
return 0;
}
总结: Block在创建时, 截获自动变量是用底层的成员变量保存自动变量的瞬时值, 因此在Block的函数内部, 是无法直接修改原自动变量的值的(因为修改的是Block的成员变量). 同时, 在Block语法执行以后, 再修改外部自动变量的值, 是不会影响Block内部截获的自动变量的值的.
参考资料
- <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>
- https://blog.csdn.net/deft_mkjing/article/details/53149629