GCD 詳解

常用的

  1. dispatch_get_main_queue 主隊列
  2. dispatch_get_global_queue 全部并發(fā)的隊列

通常的基本用法:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 執(zhí)行 耗時的任務(wù)
        dispatch_async(dispatch_get_main_queue(), ^{

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

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

首先:

三個不設(shè)置優(yōu)先級的全局隊列.png

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

優(yōu)先級:
全局隊列第一個參數(shù):


優(yōu)先級.png

設(shè)置優(yōu)先級后的效果

設(shè)置優(yōu)先級.png

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

串行隊列,執(zhí)行是有順序的。

串行隊列.png

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

參數(shù) 第二個參數(shù) 兩種:

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

修改參數(shù)后就是并行的隊列,三個線程并發(fā)執(zhí)行。

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

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

多個接口并發(fā)執(zhí)行,我想在所有接口都回調(diào)完成后刷新UI,怎么做?

兩種解決方法:

  1. 加入標(biāo)記位
  2. GCD的 dispatch_group_t

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

dispatch_group_t.png

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

主線程刷新UI.png

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


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


那么我們模擬兩個數(shù)據(jù)請求接口


模擬兩個數(shù)據(jù)請求.png

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

加入數(shù)據(jù)接口請求方法.png

看輸出結(jié)果,好像跟我們預(yù)期的不太一樣啊。在1、2任務(wù)剛開始的時候就提示全部完成了,然后刷新UI,刷新完后才真正的完成數(shù)據(jù)回調(diào)處理數(shù)據(jù)啊。感覺不對啊~~~?。≡趺崔k?

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

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

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

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

總結(jié):

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容