现在 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访问外界变量
- MRC 环境下:访问外界变量的 block 默认是存储在栈中;
- ARC 环境下:访问外界变量的 block 默认存放在堆中;实际上是会先放在栈区,在ARC的情况下自动拷贝到堆区,自动释放。
使用 copy 修饰符的作用就是将 block 从栈区拷贝到堆区。复制到堆区主要是为了保存 block 的状态,延长它的生命周期,如果 block 在栈上的话,其所属的变量作用域一旦结束,这个 block 就会被释放掉,block 中的 __block 变量也会被释放掉。为防止 block 在其变量作用域结束之后被释放掉,将其复制到堆中。