更新记录
前言
最近在重新且仔细地阅读《Objective-C 高级编程 iOS与OS X多线程和内存管理》,在阅读到 2.2 Blocks模式 这章时,看到Block中截获自动变量,对其进行重新赋值,会报“缺失__block修饰符”的编译错误。这引起了我的一些思考,在此叙述一下我的思考。
思考
举书上的一个例子
block中使用该对象
id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{
id obj = [[NSObject alloc] init];
[array addObject:obj];
};
block中对对象进行重新赋值
id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{
array = [[NSMutableArray alloc] init];
};
- 编译报错:Variable is not assignable (missing__block type specifier)
- 网上很多参考资料上都说,给该变量加上__block修饰符就可以解决问题了。但是都没有谈到这个问题的深入之处
底层思考
- 参考《Objective-C 高级编程 iOS与OS X多线程和内存管理》后续章节对Blocks的实现,我们可以知道,Blocks生成的结构体会捕获所用到的变量。
- 内存指示图

- 对于局部变量,Blocks默认捕获的是这个局部变量的值(即MemoryObj), 可以通过对MemroyObj这个地址上的内容进行修改(本质是运用了C语言的*运算符)
- 而添加了__block说明符,则Blocks捕获的是这个局部变量的内存地址,即Memroy值(C语言中使用&操作取得一个变量的地址),这样Blocks在内部就可以通过对Memory上的数据对修改(*memroy = xxx),且可以影响到Blocks外部。

- 没有用__block修饰的局部变量,在Blocks内部捕获了,即使修改了也没有任何意义(外部不受影响),所以编译器当初就设计了这个编译报错,避免产生不可预知的bug。
Block中修改局部变量的值为什么必须声明为__block类型
原文:https://www.cnblogs.com/HelloGreen/p/12684033.html