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