不捕获任何变量
1 2 3 4 5
| int main() { void (^blk)(void) = ^{printf("Block\n");}; blk(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| struct block_struct { block_struct(void *fp) { this.FuncPtr = fp; } };
static void block_imp(block_struct *self) { printf("Block\n"); }
int main() { block_struct blk(block_imp); blk.FuncPtr(blk); }
|
- Block 的内容被转化为 1 个全局函数
- Block 本身被转为一个 struct,其构造函数传入这个全局函数的地址
- Block 的调用等同于,调用 struct 的函数实现,参数是自身
捕获局部变量
1 2 3 4 5 6
| int main() { int val = 5; void (^blk)(void) = ^{printf("%d\n", val);}; blk(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| struct block_struct { int val; block_struct(void *fp, int _val):val(_val) { this.FuncPtr = fp; } };
static void block_imp(block_struct *self) { printf("%d\n", self->val); }
int main() { int val = 5; block_struct blk(block_imp, val); blk.FuncPtr(blk); }
|
- 不同之处是转换后的结构体多了一个 int 的成员变量,构造函数和函数实现也相应的变化了
- 因为是值复制,所以无法在 Block 对捕获的简单类型值进行赋值
捕获全局变量、静态全局变量、静态局部变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int global_val = 10; static int static_global_val = 10; int main() { static int static_val = 10; void (^blk)(void) = ^{ printf("%d\n", global_val); printf("%d\n", static_global_val); printf("%d\n", static_val); }; global_val = 18; static_global_val = 18; static_val = 18; blk(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| int global_val = 10; static int static_global_val = 10; struct block_struct { int *static_val; block_struct(void *fp, int _static_val):static_val(_static_val) { this.FuncPtr = fp; } };
static void block_imp(block_struct *self) { printf("%d\n", global_val); printf("%d\n", static_global_val); printf("%d\n", *(self->staic_val)); }
int main() { static int static_val = 10; block_struct blk(block_imp, &static_val); global_val = 18; static_global_val = 18; static_val = 18; blk.FuncPtr(blk); }
|
- 对于全局变量,
block_struct
没有增加变量;对于局部静态变量,存储的是指针
- 这样就可以在 Block 内部任意的修改这些值
捕获 __block
变量
1 2 3 4 5 6 7
| int main() { __block int val = 10; void (^blk)(void) = ^{printf("%d\n", val);}; val = 1; blk(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| struct block_struct { block_val *val; block_struct(void *fp, int _val):val(_val) { this.FuncPtr = fp; } };
struct block_val { block_val *forwarding; int val; };
static void block_imp(block_struct *self) { printf("%d\n", self->val->forwarding->val); }
int main() { block_val val(&val, 10); block_struct blk(block_imp, val); (val.forwarding->val) = 1; blk.FuncPtr(blk); }
|
__block
变量被转为一个类
- 无论是 Block 内还是外,访问值都得通过 forwarding 指针
- Block 得到的是一个对象的指针,因此读写方面可以和 Block 外部的值保持一致
这个例子中 forwarding 指针都是自己,不能体现其意义,那么 forwarding 指针有什么用呢?
我们知道,当对一个栈 Block 进行 copy 时,copy 函数会返回一个堆 Block。
copy 调用的时候,会将此堆 Block 访问到的 block_val
的 forwarding 指针,指向堆 Block 新生成的 block_val
,而堆 Block 自己的 block_val
的 forwarding 指针会指向自己
这样原本在栈上的 block_val
,或者是堆 Block 的 block_val
,访问到的对象都会是同一个
1 2 3 4
| __block int val = 0; void (^blk)(void) = [^{++val;} copy]; ++val; blk();
|
1 2 3 4 5
| block_val val(&val, 0); block_struct temp(block_imp, val); block_struct blk = _Block_copy(temp); (val.forwarding->val)++; blk.FuncPtr(blk);
|
捕获对象
__strong
类型的对象
1 2 3 4 5 6 7
| int main() { id array = [NSMutableArray new]; void (^blk)(void) = ^{NSLog(@"array count = %ld",[array count]);}; [array addObject:[NSObject new]]; blk(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| struct block_struct { id __strong array; block_struct(void *fp, int _array):array(_array) { this.FuncPtr = fp; } };
static void block_imp(block_struct *self) { NSLog(@"array count = %ld",[self->array count]); }
int main() { id array = [NSMutableArray new]; block_struct blk(block_imp, array); [array addObject:[NSObject new]]; blk.FuncPtr(blk); }
|
- 截获对象时,Block 内部的成员变量是用 strong 修饰,会使变量的引用计数加 1
- Block 释放时,自然也会对使该变量的引用计数 -1
- 如果对这个 Block 进行 copy,那么栈 Block 会变成堆 Block,Block 本身的引用计数会 +1,不过这个例子没有体现
__block
+ __strong
类型的对象
1 2 3 4 5 6 7
| int main() { __block id array = [NSMutableArray new]; void (^blk)(void) = ^{NSLog(@"array count = %ld",[array count]);}; [array addObject:[NSObject new]]; blk(); }
|
1 2 3 4 5
| struct block_val { block_val *forwarding; id array; };
|
和捕获 __block
一样,只是 block_val
内部维护的是一个对象