声明 block 属性的时候为什么用 copy

现在 iOS 开发中 block 横行,但是在使用的时候还是有很多要注意的。虽然一直在使用 block,但是一直有一个疑问:为什么声明 block 属性的时候要用 copy?

1
@property (nonatomic, copy) void (^blockName)(void);

block 的3种类型

全局块(_NSConcreteGlobalBlock)

全局快是存储在静态区的,这个静态区也叫做全局区,相当于 Objective-C 中的单例。

栈块(_NSConcreteStackBlock)

栈块是存储在栈区的,超出作用域就会被销毁。

堆块(_NSConcreteMallocBlock)

堆块会存储在堆区中,它是一个带有引用计数的对象,需要自行管理其内存。

判断 block 的存储位置

block 不访问外界变量,这个外界变量包括栈中和堆中的变量;

block 既不在栈中也不在堆中,这样就是全局块,在 ARC 和 MRC 下都是如此。

block访问外界变量

  1. MRC 环境下:访问外界变量的 block 默认是存储在栈中;
  2. ARC 环境下:访问外界变量的 block 默认存放在堆中;实际上是会先放在栈区,在ARC的情况下自动拷贝到堆区,自动释放。

使用 copy 修饰符的作用就是将 block 从栈区拷贝到堆区。复制到堆区主要是为了保存 block 的状态,延长它的生命周期,如果 block 在栈上的话,其所属的变量作用域一旦结束,这个 block 就会被释放掉,block 中的 __block 变量也会被释放掉。为防止 block 在其变量作用域结束之后被释放掉,将其复制到堆中。