在iOS 4.0以后,GCD开始以飞快的普及率出如今众多开发者的代码中。因为它提供了更易于使用的并发模型,而不只仅是上面讲到的线程锁,这就使得不少线程处理的陷阱得以有效避免,同时在libdispatch库中,苹果提供了大量的API,大大下降了程序员的使用难度,以及提升功能的健壮性,从而不多开发人员的青睐。java
谈到GCD(Grand Central Dispatch)不少开发者都不陌生,这是一个与block语法块结合十分紧密的多线程技术,它拥有丰富的语言特性,多样的库供开发者使用,对于硬件上多核处理器提供了普遍地系统级别的优化,在多核的iOS和OS X硬件体系中,高并发执行能力获得有效地提高。同时它提供了一种抽象的线程,而这种抽象是基于“调度队列”(dispatch queue)。开发者不须要关心线程中具体实现了哪些细节,由于系统框架已经将block语法块加入到队列中,由GCD统一负责处理全部事务。程序员
GCD是基于block语法块与c库函数的技术。若是想熟练使用GCD必须首先对block有充分的了解,否则很容易形成不少问题,好比本文以前提到的内存的引用环,这在若是线程中发生这种问题是十分致命的,由于开发者很难掌控子线程的生命周期,或者说,开发者并不能准确地肯定线程中地代码什么时候能执行完毕,这就会到这大量内存泄漏。因此在学习GCD前,首先了解block这个相当重要。swift
Block语法块这个概念由来已久,也并不是只有objective-c的语法独有的,这个语言的特性是做为延展加入到GCC编译器中的。从技术层面来说block更接近与c语言层面的特性。在Mac OS X 10.6以及iOS4.0以后的版本以后支持block语法。在java,或是近来比较火热的swift语法中,block对象会被称之为“闭包”(closure)。而在oc中,开发者更习惯将他叫作“语法块”,或者直接称之为“块”。xcode
Block的语法特色:性能优化
使用块的场景有不少,好比做为传统的函数回调,以及访问所须要的做用域内的局部变量,而不是须要使用一个开发者想要执行操做时集成“上下文”(context)的数据来进行回调。网络
Block语法和标准c语言函数极为相似,但不一样的是,Block语法块的做用域处于定义它的函数之中。以下代码。多线程
/** * 构建一个加法运算的block语法块 * * @param firstNum 输入第一个字符 * @param secondNum 输入第二个字符 * * @return 返回两个数的和 */ int (^sumNumbers)(int firstNum,int secondNum) = ^(int firstNum,int secondNum){ return firstNum+secondNum; }; /** * 调用block语法 * 计算10+13之和 */ NSLog(@"sumNumbers = %d",sumNumbers(10,13)); 打印结果:2015-06-23 16:59:06.511 iOS性能优化[54212:628205] sumNumbers = 23
若是在Block做用域以外的一个变量须要在Block块中修改自身的值,就须要用到__block这个修饰符了,以下代码。闭包
/** * 定义一个外部变量 */ int __block multNumbers = 0; /** * 构建一个加法运算的block语法块 * * @param firstNum 输入第一个字符 * @param secondNum 输入第二个字符 * * @return 返回两个数的和 */ int (^sumNumbers)(int firstNum,int secondNum) = ^(int firstNum,int secondNum){ multNumbers = firstNum*secondNum; return firstNum+secondNum; }; /** * 调用block语法 * 计算10+13之和 * 输出修改后的multNumbers的值 */ NSLog(@"sumNumbers = %d , multNumbers = %d",sumNumbers(10,13),multNumbers);
若是不加这个修饰符的话,xcode则会抛出这样的错误,如图2.4。并发
图2.4 不使用修饰符__block xcode抛出错误框架
此外Block语法还能够经过外部声明,在不一样的地方是使用同一个命名的block,这种方法极为经常使用,并且十分灵活,以下代码。
enum CountNumbersType { CountNumbersTypeSum, //加法 CountNumbersTypeSub, //减法 CountNumbersTypeMult, //乘法 CountNumbersTypeDivision //除法 }; //定义枚举类型 typedef enum CountNumbersType CountNumbersType; /** * 声明计算block * * @return 返回计算结果 */ typedef int(^CountNumbers)(int,int,CountNumbersType); { /** * 定义block内方法 * * @param firstNum 第一个参数数字 * @param secondNum 第二个参数数字 * @param type 运算类型枚举值 * * @return 运算返回值 */ CountNumbers countNumbers = ^(int firstNum,int secondNum,CountNumbersType type){ switch (type) { case CountNumbersTypeSum: return firstNum + secondNum; break; case CountNumbersTypeSub: return firstNum - secondNum; break; case CountNumbersTypeMult: return firstNum * secondNum; break; case CountNumbersTypeDivision: return firstNum / secondNum; break; default: return 0; break; } }; /** * 打印输出结果 * * @param sum 相加结果 * @param sub 相减结果 * @param mult 相乘结果 * @param division 相除结果 * * @return 打印输出结果 */ NSLog(@"sum = %d,sub = %d,mult = %d,division = %d.", countNumbers(10,5,CountNumbersTypeSum), countNumbers(10,5,CountNumbersTypeSub), countNumbers(10,5,CountNumbersTypeMult), countNumbers(10,5,CountNumbersTypeDivision)); } 打印结果:2015-06-23 18:19:12.016 iOS性能优化[58960:679603] sum = 15,sub = 5,mult = 50,division = 2.
在不少状况下,block对象还能够被看成参数进行传递,下面要讲的GCD就是这样作的,还有AFNetWork 2.0使用的参数也是block回调,固然开发者也能够本身写这样的方法,以下模拟网络请求代码。
经过上面代码能够看出,使用block做为回调函数,使用起来十分简便,但使用block必定须要注意的是:
避免内存管理上面的循环引用。
注意block的异步性,这里提到的异步性和多线程的异步并不相同,而是代码执行方面,block块中的代码执行于它所定义的代码区域并不是顺序执行,这点尤其须要注意,不然会形成问题。