GCD是一套高度抽象化的多線程編程技術,使用它可以編寫出高效的多線程代碼。相比於 NSThread 和 Cocoa NSOperation,Apple更推薦我們使用GCD。GCD的適用范圍通常是那種需要長時間CPU運算的場合,例如耗時較長的圖形處理和算法執行。GCD有兩寶:一個Dispatch Queue(FIFO隊列)和一個線程池,前者用來添加任務,後者用來執行任務。
Dispatch Queue也是一個對象(可以調用dispatch_retain和dispatch_release來進行保留和釋放),它會按照先進先執行的順序執行任務。任務一般都是block。在使用GCD的時候,我們常常會先創建一個Dispatch Queue,然後向它提交block。看起來很像我們創建一個數組對象然後往裡添加元素。Dispatch Queue可以是並發的,也可以是串行的。
-並發的DQ:在底層,線程池會提供多個線程來執行任務,所以可以按序啟動多個任務並發執行;
-串行的DQ:線程池只提供一個線程用來執行任務,所以後一個任務必須等到前一個任務執行結束才能開始;
我們使用的Dispatch Queue有以下幾種:
Global Queue-全局並發隊列,由整個進程共享。隊列中的任務按照FIFO順序執行,同一時間可同時執行多個任務。
// 第1個參數表示隊列執行的優先級: // DISPATCH_QUEUE_PRIORITY_HIGH-高優先級 // DISPATCH_QUEUE_PRIORITY_DEFAULT-中優先級 // DISPATCH_QUEUE_PRIORITY_LOW-低優先級 // DISPATCH_QUEUE_PRIORITY_BACKGROUND-最低優先級 // 第2個參數暫不支持,傳0即可; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);Main Queue-主線程隊列,屬於串行隊列。隊列中的任務按照FIFO順序在主線程中執行,因為是串行隊列,同一時間只能執行一個任務。
dispatch_queue_t queue = dispatch_get_main_queue();用戶隊列-用戶自定義創建,可並發可串行。同樣的隊列中的任務按照FIFO順序執行。
// 第一個參數: // 隊列ID,需要傳遞一個字符串,命名分格采用類似com.example.myqueue的格式; // 第二個參數: // 在ios 4.3以前不支持,傳NULL即可; // 在ios 4.3以後,這個參數表示隊列類型。DISPATCH_QUEUE_SERIAL-創建一個串行隊列;DISPATCH_QUEUE_CONCURRENT-創建一個並發隊列; dispatch_queue_t queue = dispatch_queue_create("", NULL);
常用的GCD接口有哪些?
1、dispatch_async
作用:提交block至指定的隊列中並異步執行,函數在第一時間返回。常見用法如下
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗時的操作 dispatch_async(dispatch_get_main_queue(), ^{ // 更新界面 }); });2、dispatch_group_async(1) / dispatch_group_wait (2)/ dispatch_group_notify(3)
作用:(1)提交block至指定隊列中並和一個dispatch_group_t對象關聯,函數異步執行將在第一時間返回;
(2)同步等待至指定group中的block執行完畢或執行超時函數才返回;
(3)設置觀察某個指定的group,等group中的block全部執行完畢後,向指定的queue提交block並異步執行;
這3個方法常常是搭配使用的,例如dispatch_group_async/dispatch_group_wait搭配
// 創建隊列和組 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 向隊列中添加block並關聯組 dispatch_group_async(group, queue, ^{ // 耗時操作1 }); dispatch_group_async(group, queue, ^{ // 耗時操作2 }); // ... // 同步等待指定group執行完畢或超時 // 超時時間可以設為:DISPATCH_TIME_FOREVER-永遠不超時;DISPATCH_TIME_NOW-很短時間內即超時; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 後續操作,如更新界面 // ...dispatch_group_async/dispatch_group_notify搭配使用
// 創建隊列和組 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // 向隊列中添加block並關聯組 dispatch_group_async(group, queue, ^{ // 耗時操作1 }); dispatch_group_async(group, queue, ^{ // 耗時操作2 }); // ... // group中的block全部完成後添加block至queue;group可以不在queue中; // dispatch_group_notify是異步的; dispatch_group_notify(group, queue, ^{ // 耗時操作3 }); // 後續操作,如更新界面 // ...3、dispatch_apply
作用:提交一個block至指定隊列並循環調用多次,直到所有的調用都執行完畢函數才返回。使用方法例如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 此方法會讓主線程同步等待至所有循環調用block都執行完畢才返回 // 在這裡,queue最好是傳遞一個並發隊列才能發揮這個方法的最大優勢 // index表示循環次數 dispatch_apply(5, queue, ^(size_t index) { }); // 後續操作,如更新界面 // ...
4、dispatch_barrier_async
作用:提交block到指定隊列並異步執行,函數將在第一時間返回;如果這個隊列是通過dispatch_queue_create方法創建的並發隊列,則這個block要等到它隊列前面的所有block執行完畢才會執行,排在這個block後面的block也要等到該block執行完畢才能執行;如果這個隊列不是上述隊列,則dispatch_barrier_async效果等同於dispatch_async。使用形式形如
dispatch_queue_t queue = dispatch_queue_create("com.zwxx.tiancai", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ // some code }); dispatch_barrier_async(queue, ^{ // some code }); dispatch_async(queue, ^{ // some code });5、dispatch_once
作用:在應用程序的整個生命周期內只執行一次指定的block。常用它實現單例模式
+ (MyObject *)sharedMyObject { static MyObject *_singleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _singleton = [[MyObject alloc] init]; }); return _singleton; }