Block中修改局部变量的值为什么必须声明为__block类型

更新记录

时间 版本修改
2020年4月12日 初稿

前言

最近在重新且仔细地阅读《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。

猜你喜欢

转载自www.cnblogs.com/HelloGreen/p/12684033.html
今日推荐