GCD 詳解

常用的

  1. dispatch_get_main_queue 主隊列
  2. dispatch_get_global_queue 全部并發的隊列

通常的基本用法:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 執行 耗時的任務
        dispatch_async(dispatch_get_main_queue(), ^{

             // 執行完成后,回到主線程 刷新UI
            
        });
        
    });

主隊列就不介紹了,直接說全局隊列
dispatch_get_global_queue 有兩個參數,第二個沒什么用,蘋果留給以后的擴展,第一個參數就是優先級了,在NSThread里面有設置優先級的屬性Priority,在GCD里當然也是有的。

首先:

三個不設置優先級的全局隊列.png

可以看得出 dispatch_get_global_queue 是同時運行的,順序也是不確定的。說明它是一個全局并發的隊列
再看它的線程id,是三個不同的id,所以說明是創建了三個線程,然后異步執行。

優先級:
全局隊列第一個參數:


優先級.png

設置優先級后的效果

設置優先級.png

我們給2設置了最高級別,但是卻是3先開始的,但是結束的時候是2先結束的,所以說這個優先級設置也是有一定概率的,一般情況下優先級高的會比優先級低的先執行完。
但是 如果線程執行的任務復雜度不同,那么就會出現混亂的問題,因為還是為了保持一個順序的話,那么我們就需要用到串行的隊列了。GCD也給們我提供了串行的隊列

串行隊列,執行是有順序的。

串行隊列.png

可以看的出來我們自己創建的隊列queue 默認是串行的。兩個參數,第一個是唯一標識,第二個就是設置 串行、并行。NULL默認為串行的。
看打印出來的結果 和 時間,可以看出來是串行的隊列,一個執行完成再執行另一個的。
還有個重點:這是在一個線程里面執行的。不知道大家有沒有看出來,你們看下面的線程id號是一樣的。

參數 第二個參數 兩種:

  1. DISPATCH_QUEUE_CONCURRENT 并行
  2. DISPATCH_QUEUE_SERIAL 串行
并行隊列.png

修改參數后就是并行的隊列,三個線程并發執行。

學了這些,有沒有一些問題呢? 首先呢,對于串行隊列,我們可以在所有任務都完成的時候回到主線程然后去做一些其他的工作,你們有沒有想一個問題:

實際開發中:有這種串行的隊列開發的應用嗎?沒有吧,這樣會阻塞當前線程,造成用戶體驗不好。實際開發中都是并行隊列,異步執行。
那么問題來了:

多個接口并發執行,我想在所有接口都回調完成后刷新UI,怎么做?

兩種解決方法:

  1. 加入標記位
  2. GCD的 dispatch_group_t

我們這里講第二種。
GCD的dispatch_group_t就是為了解決多個接口并發執行,在最后執行完成 給予 回調 的問題的。
為什么呢?因為 它有個 dispatch_group_notify 這個方法,它會在隊列中所有異步線程請求完后 回調?。。【褪沁@么流弊。

dispatch_group_t.png

代碼就是這樣的,看輸出臺,是不是在所有并發隊列請求完成后回調的?si bu si ?
但是有個問題,不知道大家注意了沒有,我們的notify回調不是在主線程中執行的,它是在系統分配在最后一個完成的隊列中回調提示的。
所以解決辦法就是把notify 方法的第二個參數換成主線程。

主線程刷新UI.png

上面的不貼了,看效果是不是。


小tips:
因為GCD是自動控制線程的生命周期的,我們不需要關心線程的一些屬性,所以一般主線程的name是main,所以的子線程的name都是null。


那么我們模擬兩個數據請求接口


模擬兩個數據請求.png

這時候我們就可以把這兩個請求數據的方法 放入到我們的 異步請求里面了。

加入數據接口請求方法.png

看輸出結果,好像跟我們預期的不太一樣啊。在1、2任務剛開始的時候就提示全部完成了,然后刷新UI,刷新完后才真正的完成數據回調處理數據啊。感覺不對啊~~~!!怎么辦?

其實仔細看你會發現,我們的這兩個請求的Block都是異步請求對吧!然后把這兩個異步請求放入到異步請求里面。這樣就形成了異步套異步啊。?。。。。《???外層異步不會持有request,所以外層的兩個異步會瞬間完成,然后我們的dispatch_group_notify 會直接回調完成。但是在內層的請求卻還在進行著。。。。那么我們改成同步group?呵呵告訴你沒有dispatch_group_sync這方法,你自己創造去吧!呵呵噠!

那么怎么解決這樣的問題呢?

  1. dispatch_group_enter();
  2. dispatch_group_leave();
完美.png

這兩個方法。1是在整個異步請求的過程中group持有 2是在異步請求完成后不在持有。所以這兩行代碼的意思就是把這個異步請求放入到group當中。 這樣就和我們預期的效果是一樣的了。

總結:

  1. dispatch_get_main_queue 主隊列
  2. dispatch_get_global_queue 全局隊列 有兩個參數,第一個設置優先級,第二個目前沒用。
  3. dispatch_async 異步執行
    dispatch_sync 同步執行
  4. dispatch_queue_create 創建一個隊列 第一個參數是唯一標識,第二個是優先級。對象是dispatch_queue_t類型。
  5. dispatch_group_async 異步執行組隊列
    dispatch_group_enter 從某時開始持有
    dispatch_group_leave 到某時不在持有
  6. dispatch_group_create 創建一個組 沒有參數,對象是dispatch_group_t類型
  7. dispatch_group_notify 組內所以隊列完成后 回調。注意,回調的不是在主線程中,需要UI刷新的 比如切到主線程中。

從以上的學習、分析,我們好像根本沒有像NSThread的那種去創建見一個線程,去設置線程的屬性,管理線程的生命周期。對吧!所以說GCD 是不需要去管理線程的。我只要是創建隊列和組,告訴去干什么就可以了。是不是很容易,雖然代碼可讀性差。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. GCD簡介 iOS開發中多線程的API主要有pthread,NSThread,NSOperation和GCD...
    安東_Ace閱讀 1,296評論 0 6
  • 目錄:iOS多線程(一)--pthread、NSThreadiOS多線程(二)--GCD詳解iOS多線程(三)--...
    Claire_wu閱讀 1,096評論 0 6
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個最簡單的問題,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,831評論 1 17
  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 854評論 0 3
  • 去年火了一首歌,《南山南》,人們開始瘋狂找原唱,叫馬頔,于是他也火了,幾乎是一夜之間就火了。 人一火好像就難免漂浮...
    左耳蟲蟲閱讀 453評論 0 0