在OC中, block代码块有三种不同类型。
1._NSConcreteGlobalBlock
全局的静态block,不会访问外部的变量。就是说block没有调用其他的外部变量。
2._NSConcreteStackBlock
保存在栈中的 block,当函数返回时会被销毁。这个block就是没有被赋值,并且block访问了外部变量。
3._NSConcreteMallocBlock
保存在堆中的 block,当引用计数为 0 时会被销毁,对_NSConcreteStackBlock 执行copy得来的。
block 使用copy 修饰的原因:
我们知道,函数的声明周期是随着函数调用的结束就终止了。我们的block是写在函数中的。
如果是全局静态block的话,他直到程序结束的时候,才会被被释放。但是我们实际操作中基本上不会使用到不访问外部变量的block(_NSConcreteGlobalBlock)。
如果是保存在栈中的block,他会随着函数调用结束被销毁。从而导致我们在执行一个包含block的函数之后,就无法再访问这个block。因为(函数结束,函数栈就销毁了,存在函数里面的block也就没有了),我们再使用block时,就会产生空指针异常(_NSConcreteStackBlock)。
如果是堆中的block,也就是copy修饰的block。他的生命周期就是随着对象的销毁而结束的。只要对象不销毁,我们就可以调用的到在堆中的block(_NSConcreteMallocBlock)。
这就是为什么我们要用copy来修饰block。因为不用copy修饰的访问外部变量的block,只在他所在的函数被调用的那一瞬间可以使用。之后就消失了。
block 什么时候被自动copy
作为变量:
一个 block 刚声明的时候是在栈上
赋值给一个普通变量之后就会被 copy 到堆上
赋值给一个 weak 变量不会被 copy
函数传参:
作为参数传入函数 block不会被 copy
作为函数的返回值 block会被 copy
针对 block 做为参数 传入函数 block 不会被copy,这些知名的开源库是这么做的
这里写图片描述