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塊中的代碼執行於它所定義的代碼區域並不是順序執行,這點尤其須要注意,不然會形成問題。

相關文章
相關標籤/搜索