Block是C语音级别和运行时放面的一个特征。Block封装了一段代码逻辑,也用{}括起,和标准C语音中的函数/函数指针很相似,此外就是block能够对定义环境中的变量可引用到。这一点和"闭包"概念类似。
block有很多应用场景,如对代码封装作为参数传递。这在使用dispatch并发(Operation中也有BlockOperation)和completion异步回调等处都广泛应用。
1.Block的基本使用
声明: (返回类型)(^声明的block名称)(参数列表);
实现: ^(参数列表){代码块}
建议出现多次的block使用typedef定义。
block的调用: block名称(参数列表);
2.使用中的注意点
(1)对定义环境的变量使用。默认是以const的方式使用,这有点像函数的const参数传递,如过需要block内修改可变,则使用__block,这样做存储就实现了共享,包括块中的递归应用和定义环境上下文中的多个block使用。block通常定义在栈帧当中,而当所处的栈帧被销毁的时候,block以及引用到的__block变量将会依然有效。
(2)引用类型问题。block中的引用默认都是强引用,必要的时候需要使用__weak,同delegate使用的注意一样,避免循环引用。此外,苹果文档中还给出了对instanceVariable和对localVariable引用不同的例子,注意体会下。
(3)copy。在类属性中,要使用copy。此外,对block进行copy要使用Block_copy()/Block_release()。
3.联想Java中匿名类使用
Java7以及之前的各个版本中,没有“闭包”的概念(感兴趣的可以看今年3月Oracle发布的Java8),回调(callback)使用内部类实现。在方法定义中使用匿名内部类,需要注意的一点是匿名类中对外部方法参数的使用,要求参数只能是final的。
其实在iOS中,对于block使用外部方法的参数,也只能是const的,不能对参数进行__block要求。
4.Block与对象的关系
Block是OC语言中的对象。Block对象与一般的类实例对象有所不同,一个主要的区别就是分配的位置不同,block默认在栈上分配,一般类的实例对象在堆上分配。
retain是对一个在堆中分配内存的对象的引用计数做了增加,执行release操作的时候检查计数是否为1,如果是则释放堆中内存。而对于在栈上分配的block对象,这一点显然有所不同,如果方法调用返回,栈帧上的数据自然会作废处理,不像堆上内存,需要单独release,就算NSArray对block对象本身做了retain也无济于事。
用一个方法对block数组做初始化是否有可能方案呢。答案是肯定的,不过需要真正了解block的使用,至少要会用Block_copy()和Block_release()。
5.Block的类型和使用
NSGlobalBlock 显示的是没有对周围变量没有引用的Block。
NSStackBlock 是其中加入了对定义环境变量的引用。
NSMallockBlock 对一个NSStackBlock对象使用了Block_copy()或者发送了copy消息,就会得到NSMallocBlock。
对于Global的Block,我们无需多处理,不需retain和copy,因为即使你这样做了,似乎也不会有什么两样。对于Stack的Block,如果不做任何操作,就会向上面所说,随栈帧自生自灭。而如果想让它获得比stack frame更久,那就调用Block_copy(),让它搬家到堆内存上。而对于已经在堆上的block,也不要指望通过copy进行“真正的copy”,因为其引用到的变量仍然会是同一份,在这个意义上看,这里的copy和retain的作用已经非常类似
在类中,如果有block对象作为property,可以声明为copy。
参考:http://www.molotang.com/articles/1691.html