2.2 更易用的多线程——GCD

在iOS 4.0以后,GCD开始以飞快的普及率出如今众多开发者的代码中。因为它提供了更易于使用的并发模型,而不只仅是上面讲到的线程锁,这就使得不少线程处理的陷阱得以有效避免,同时在libdispatch库中,苹果提供了大量的API,大大下降了程序员的使用难度,以及提升功能的健壮性,从而不多开发人员的青睐。java

2.2.1 GCD是什么?

谈到GCD(Grand Central Dispatch)不少开发者都不陌生,这是一个与block语法块结合十分紧密的多线程技术,它拥有丰富的语言特性,多样的库供开发者使用,对于硬件上多核处理器提供了普遍地系统级别的优化,在多核的iOS和OS X硬件体系中,高并发执行能力获得有效地提高。同时它提供了一种抽象的线程,而这种抽象是基于“调度队列”(dispatch queue)。开发者不须要关心线程中具体实现了哪些细节,由于系统框架已经将block语法块加入到队列中,由GCD统一负责处理全部事务。程序员

GCD是基于block语法块与c库函数的技术。若是想熟练使用GCD必须首先对block有充分的了解,否则很容易形成不少问题,好比本文以前提到的内存的引用环,这在若是线程中发生这种问题是十分致命的,由于开发者很难掌控子线程的生命周期,或者说,开发者并不能准确地肯定线程中地代码什么时候能执行完毕,这就会到这大量内存泄漏。因此在学习GCD前,首先了解block这个相当重要。swift

2.2.2  什么是Block

Block语法块这个概念由来已久,也并不是只有objective-c的语法独有的,这个语言的特性是做为延展加入到GCC编译器中的。从技术层面来说block更接近与c语言层面的特性。在Mac OS X 10.6以及iOS4.0以后的版本以后支持block语法。在java,或是近来比较火热的swift语法中,block对象会被称之为“闭包”(closure)。而在oc中,开发者更习惯将他叫作“语法块”,或者直接称之为“块”。xcode

Block的语法特色:性能优化

  1. 如同c语言函数同样,拥有参数以及参数类型,同时拥有返回值与返回值类型。
  2. 加入到块中的语法将会被块强引用,并持有,直到块被销毁。
  3. 能够捕捉它所定义的做用域范围的状态,并传递到其余做用域。

使用块的场景有不少,好比做为传统的函数回调,以及访问所须要的做用域内的局部变量,而不是须要使用一个开发者想要执行操做时集成“上下文”(context)的数据来进行回调。网络

2.2.3  Block基础知识

 

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块中的代码执行于它所定义的代码区域并不是顺序执行,这点尤其须要注意,不然会形成问题。

相关文章
相关标签/搜索