前言
默认为MRC 特殊情况会注明ARC模式运行
一、block
我们在Interface 和 implementation 之外定义一个globalBlock,在ViewDidLoad内部定义propertyBlock、tempBlock、copyBlock、然后运行程序输出Log如下:
我们将propertyBlock的retain修饰词更改为copy重新运行程序,输出Log与Log1相同。
将MRC切换到ARC模式重新运行程序Log输出与Log1相同。
二、block捕获局部和全局变量
1、block捕获全局变量
现在我们定义一个全局变量globalStr在上述Block(globalBlock、propertyBlock、tempBlock、copyBlock)内部Log打印,具体代码如下:
我们发现block只是捕获全局变量的话输出与Log1仍然保持一直。
2.block捕获局部变量&block属性修饰词
现在我们将globalBlock的实现放到ViewDidLoad内部,在ViewDidLoad内部定义一个局部变量,然后在globalBlock、propertyBlock、tempBlock、copyBlock、内部输出varProperty变量。
运行工程输出Log如下:
在P-2-2的基础上我们修改工程运行环境为ARC,输出Log如下:
在P-2-2的基础上我们将propertyBlock的属性修饰改为retain(weak相同),重新运行工程,输出Log如下:
在P-2-2的基础上我们将propertyBlock的属性修饰改为retain(weak相同),并将工程运行环境改为ARC,输出Log如下:
在P-2-2的基础上我们将propertyBlock的属性修饰改为strong,重新运行工程,输出Log如下:
在P-2-2的基础上我们将propertyBlock的属性修饰改为strong,并将工程运行环境改为ARC,输出Log如下:
3.block类型分析
从上面的Log中我们可以看出Apple提供了三种类型的Block,分别是:NSGlobalBlock、NSStackBlock、NSMallocBlock。充block的命名我们可以猜测这三个block分别是全局block、栈block和堆block。接下来我们来验证下是不是这样?
打开工程运行上述代码,输出Log如下:
我们可以看出NSGlobalBlock的地址为: 0x1099de0b0、NSStackBlock的地址为:0x7ffee6220a30、NSMallocBlock的地址为:0x60c00024bcd0、而在计算机中我们知道有五大分区分别是堆区、栈区、全局区、常量区、代码区,并且这五大分区是地址有高到低的。因此从上面三个block的地址顺序:NSStackBlock > NSMallocBlock > NSGlobalBlock可以大致推测出他们分别存储在栈区、堆区、和全局区。我们知道除了堆区其他分区的对象声明周期我们无法控制,而对于栈去的变量更是比较特殊因为程序执行期间栈区对象可能被出栈销毁,因此为了程序执行的安全性栈区的block一般要copy到堆区,由我们自己来管理block的生命周期。
注释:上面Log4、Log5的block是在栈去存储的,它的作用于只在ViewDidLoad函数块内有效(这个类似于局部变量),一旦我们在ViewDidLoad函数块外面调用栈去的Block程序将Crach。
如下(野指针导致访问出错程序Crach):