最詳細(xì)的GCD知識介紹

1、GCD

GCD全稱為Grand Central Dispatch,是libdispatch的市場名稱,而libdispatch是Apple的一個庫,其為并發(fā)代碼在iOS和OS X的多核硬件上執(zhí)行提供支持。確切地說GCD是一套低層級的C API,通過 GCD,開發(fā)者只需要向隊(duì)列中添加一段代碼塊(block或C函數(shù)指針),而不需要直接和線程打交道。GCD在后端管理著一個線程池,它不僅決定著你的代碼塊將在哪個線程被執(zhí)行,還根據(jù)可用的系統(tǒng)資源對這些線程進(jìn)行管理。這樣通過GCD來管理線程,從而解決線程被創(chuàng)建的問題。

2、GCD的優(yōu)勢

  • 易用: GCD 提供一個易于使用的并發(fā)模型 而不僅僅只是鎖和線程,以幫助我們避開并發(fā)陷阱,而且因?yàn)榛赽lock,它能極為簡單得在不同代碼作用域之間傳遞上下文。
  • 靈活: GCD 具有在常見模式上(比如鎖、單例),用更高性能的方法優(yōu)化代碼,而且GCD能提供更多的控制權(quán)力以及大量的底層函數(shù)。
  • 性能: GCD 能自動根據(jù)系統(tǒng)負(fù)載來增減線程數(shù)量,這就減少了上下文切換以及增加了計(jì)算效率。

3、GCD相關(guān)概念

3.1 Dispatch Objects 調(diào)度器對象

盡管GCD是純C語言的,但它被組建成面向?qū)ο蟮娘L(fēng)格。GCD對象被稱為dispatch object, 所有的dispatch objects都是OC對象.,就如其他OC對象一樣,當(dāng)開啟了ARC(automatic reference counting)時,dispatch objects的retain和release都會自動執(zhí)行。而如果是MRC的話,dispatch objects會使用dispatch_retain和dispatch_release這兩個方法來控制引用計(jì)數(shù)。

3.2 Serial & Concurrent 串行 & 并行 [‘si?ri?l] [k?n'k?r?nt]

串行任務(wù)就是每次只有一個任務(wù)被執(zhí)行,并發(fā)任務(wù)就是在同一時間可以有多個任務(wù)被執(zhí)行。

3.3 Synchronous & Asynchronous 同步 & 異步 ['si?kr?n?s] [ei'si?kr?n?s]

同步函數(shù)意思是在完成了它預(yù)定的任務(wù)后才返回,在任務(wù)執(zhí)行時會阻塞當(dāng)前線程。而異步函數(shù)則是任務(wù)會完成但不會等它完成,所以異步函數(shù)不會阻塞當(dāng)前線程,會繼續(xù)去執(zhí)行下一個函數(shù)。

3.4 Concurrency & Parallelism 并發(fā)性 & 平行 [k?n'k?r?nsi] ['p?r?leliz?m]

并發(fā)的意思就是同時運(yùn)行多個任務(wù)。這些任務(wù)可能是以在單核 CPU 上以分時(時間共享)的形式同時運(yùn)行,也可能是在多核 CPU 上以真正的并行方式來運(yùn)行。然后為了使單核設(shè)備也能實(shí)現(xiàn)這一點(diǎn),并發(fā)任務(wù)必須先運(yùn)行一個線程,執(zhí)行一個上下文切換,然后運(yùn)行另一個線程或進(jìn)程。并行則是真正意思上的多任務(wù)同時運(yùn)行。

3.5 Context Switch 上下文切換 [‘k?ntekst] [swit?]

Context Switch即上下文切換,一個上下文切換指當(dāng)你在單個進(jìn)程里切換執(zhí)行不同的線程時存儲與恢復(fù)執(zhí)行狀態(tài)的過程。這個過程在編寫多任務(wù)應(yīng)用時很普遍,但會帶來一些額外的開銷。

3.6 Dispatch Queues 調(diào)度隊(duì)列

GCD dispatch queues是一個強(qiáng)大的執(zhí)行多任務(wù)的工具。Dispatch queue是一個對象,它可以接受任務(wù),并將任務(wù)以先進(jìn)先出(FIFO)的順序來執(zhí)行。Dispatch queue可以并發(fā)的或串行的執(zhí)行任意一個代碼塊,而且并發(fā)任務(wù)會像NSOperationQueue那樣基于系統(tǒng)負(fù)載來合適地并發(fā)進(jìn)行,串行隊(duì)列同一時間則只執(zhí)行單一任務(wù)。Dispatch queues內(nèi)部使用的是線程,GCD 管理這些線程,并且使用Dispatch queues的時候,我們都不需要自己創(chuàng)建線程。Dispatch queues相對于和線程直接通信的代碼優(yōu)勢是:Dispatch queues使用起來特別方便,執(zhí)行任務(wù)更加有效率。

3.7 Queue Types 隊(duì)列類型

GCD有三種隊(duì)列類型:

類型描述

  • Serial串行隊(duì)列將任務(wù)以先進(jìn)先出(FIFO)的順序來執(zhí)行,所以串行隊(duì)列經(jīng)常用來做訪問某些特定資源的同步處理。你可以也根據(jù)需要創(chuàng)建多個隊(duì)列,而這些隊(duì)列相對其他隊(duì)列都是并發(fā)執(zhí)行的。換句話說,如果你創(chuàng)建了4個串行隊(duì)列,每一個隊(duì)列在同一時間都只執(zhí)行一個任務(wù),對這四個任務(wù)來說,他們是相互獨(dú)立且并發(fā)執(zhí)行的。如果需要創(chuàng)建串行隊(duì)列,一般用dispatch_queue_create這個方法來實(shí)現(xiàn)。
  • Concurrent并發(fā)隊(duì)列雖然是能同時執(zhí)行多個任務(wù),但這些任務(wù)仍然是按照先到先執(zhí)行(FIFO)的順序來執(zhí)行的。并發(fā)隊(duì)列會基于系統(tǒng)負(fù)載來合適地選擇并發(fā)執(zhí)行這些 任務(wù)。在iOS5之前,并發(fā)隊(duì)列一般指的就是全局隊(duì)列(Global queue),進(jìn)程中存在四個全局隊(duì)列:高、中(默認(rèn))、低、后臺四個優(yōu)先級隊(duì)列,可以調(diào) DISPATCH_QUEUE_CONCURRENT,來自己創(chuàng)建一個并發(fā)隊(duì)列。
  • Main dispatch queue與主線程功能相同。實(shí)際上,提交至main queue的任務(wù)會在主線程中執(zhí)行。main queue可以調(diào)用dispatch_get_main_queue()來獲得。因?yàn)閙ain queue是與主線程相關(guān)的,所以這是一個串行隊(duì)列。和其它串行隊(duì)列一樣,這個隊(duì)列中的任務(wù)一次只能執(zhí)行一個。它能保證所有的任務(wù)都在主線程執(zhí)行,而主線程是唯一可用于更新 UI 的線程。

4、創(chuàng)建和管理隊(duì)列

當(dāng)你決定添加一些任務(wù)到隊(duì)列中時,你需要決定該用那種類型的隊(duì)列,并且抉擇該如何使用他們。Dispatch queues可以串行或并發(fā)地執(zhí)行這些任務(wù),當(dāng)你腦海里有一個大概的思路去如何使用隊(duì)列時,你可以額快速地設(shè)置好隊(duì)列的屬性。接下來的部分,本文將告訴大家如何創(chuàng)建隊(duì)列和怎樣設(shè)置隊(duì)列的屬性。

4.1 獲取一個全局隊(duì)列

當(dāng)我們需要同時執(zhí)行多個任務(wù)時,并發(fā)隊(duì)列是非常有用的。并發(fā)隊(duì)列其實(shí)仍然還是一個隊(duì)列,它保留了隊(duì)列中的任務(wù)按先進(jìn)先出(FIFO)的順序執(zhí)行的特點(diǎn)。同時,一個并發(fā)隊(duì)列可以移除t它多余的任務(wù),甚至這些任務(wù)之前還有未完成的任務(wù)。一個并發(fā)隊(duì)列中實(shí)際執(zhí)行的任務(wù)數(shù)是由很多因素決定的,比如系統(tǒng)的內(nèi)核數(shù),其他串行隊(duì)列中任務(wù)的優(yōu)先級,以及其他進(jìn)程的工作狀態(tài)。

系統(tǒng)為每個程序提供了四種全局隊(duì)列,這些隊(duì)列中僅僅通過優(yōu)先級加以區(qū)別,這四種類型分別是高、中(默認(rèn))、低、后臺。因?yàn)檫@些隊(duì)列是全局的,所以大家不能直接創(chuàng)建它們,取而代之的是我們可以通過dispatch_get_global_queue這個方法來調(diào)用它們。


dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//全局隊(duì)列的四種類型
DISPATCH_QUEUE_PRIORITY_HIGH     [prai'?r?ti]  優(yōu)先權(quán)
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND

正如大家所看到的,因?yàn)榇嬖陉?duì)列的優(yōu)先級,所以那些在高優(yōu)先級隊(duì)列中的任務(wù)會比在默認(rèn)或低優(yōu)先級隊(duì)列中的任務(wù)要先執(zhí)行,而默認(rèn)級別隊(duì)列的優(yōu)先級又高于低優(yōu)先級隊(duì)列。注意,這里有一個比較特殊的級別容易被忽視,DISPATCH_QUEUE_PRIORITY_BACKGROUND。被設(shè)置成后臺級別的隊(duì)列,它會等待所有比它級別高的隊(duì)列中的任務(wù)執(zhí)行完或CPU空閑的時候才會執(zhí)行自己的任務(wù)。例如磁盤的讀寫操作非常耗時,如果我們不需要立即獲取到磁盤的數(shù)據(jù),我們可以把讀寫任務(wù)放到后臺隊(duì)列中,這樣讀寫任務(wù)只會在恰當(dāng)?shù)臅r候去執(zhí)行而不會影響需要更改優(yōu)先級的其他任務(wù),整個程序也會更加有效率。

Note: 盡管dispatch queues是引用計(jì)數(shù)對象,但是我們不需要用retain和release來管理全局的并發(fā)隊(duì)列。因?yàn)槿株?duì)列對于程序來說是全局的,retain和release會被全局隊(duì)列忽略。所以,我們不需要存儲這些隊(duì)列的引用數(shù),僅僅只需要在任何要使用它們的地方,調(diào)用dispatch_get_global_queue這個方法即可。

4.2 創(chuàng)建串行隊(duì)列&并發(fā)隊(duì)列

當(dāng)我們需要某些任務(wù)以指定的順序去執(zhí)行時,串行隊(duì)列是一個非常好的選擇。一個串行隊(duì)列在同一時間里只會執(zhí)行一個任務(wù),而且每次都只會從隊(duì)列的頭部把任務(wù)取出來執(zhí)行。正因?yàn)槿绱?,我們可以用串行?duì)列來替代鎖的操作,比如數(shù)據(jù)資源的同步或修改數(shù)據(jù)結(jié)構(gòu)時。和鎖不同的是,串行隊(duì)列能保證任務(wù)都是在可預(yù)見的順序里執(zhí)行,而且一旦我們在一個串行隊(duì)列里異步提交了任務(wù),隊(duì)列就能永遠(yuǎn)不發(fā)生死鎖。怎么樣,是不是很棒,不過不像并發(fā)隊(duì)列,這些串行隊(duì)列是需要我們自己創(chuàng)建和管理的。

我們還可以在程序里創(chuàng)建任意數(shù)量的隊(duì)列,不過值得注意的是,我們要盡量避免創(chuàng)建大量的串行隊(duì)列而目的僅僅是為了同時執(zhí)行隊(duì)列中的這些任務(wù)。雖然GCD 通過創(chuàng)建所謂的線程池來大致匹配 CPU 內(nèi)核數(shù)量,但是線程的創(chuàng)建并不是無代價的。每個線程都需要占用內(nèi)存和內(nèi)核資源。所以如果需要創(chuàng)建大量的并發(fā)任務(wù),我們只需要把這些任務(wù)放到并發(fā)隊(duì)列中即可。


//dispatch_queue_t
//dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

//串行隊(duì)列
dispatch_queue_t serialQueue;
serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL);

//并發(fā)隊(duì)列
dispatch_queue_t concurrentQueue;
concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
NOTE: dispatch_queue_attr_t設(shè)置成NULL的時候默認(rèn)代表串行。

4.3 獲取Main Queue

獲取主隊(duì)列的方法很簡單,如下所示:

dispatch_queue_t mainQueue;
mainQueue = dispatch_get_main_queue();

4.4 創(chuàng)建隊(duì)列的自定義上下文

所有的dispatch objects(包括dispatch queues)允許我們關(guān)聯(lián)自定義的上下文。我們可以通過使用 dispatch_set_context和dispatch_get_context這兩個方法,來為objects設(shè)定和獲取這些上下文數(shù)據(jù)。因?yàn)橄到y(tǒng)不會使用我們自定義的數(shù)據(jù),所以我們需要在適當(dāng)?shù)臅r候生成和銷毀這些數(shù)據(jù)。對于隊(duì)列,我們可以使用上下文來為一個OC對象或其他數(shù)據(jù)結(jié)構(gòu)存儲一個指針,以此來作為某個隊(duì)列的唯一標(biāo)識。我們可以在隊(duì)列銷毀前并在隊(duì)列最后執(zhí)行的方法中去銷毀上下文數(shù)據(jù)。


void myFinalizerFunction(void *context)
{
    MyDataContext* theData = (MyDataContext*)context;
    // 清除這個數(shù)據(jù)的內(nèi)容
    myCleanUpDataContextFunction(theData);
    // 釋放數(shù)據(jù).
    free(theData);
}

dispatch_queue_t createMyQueue()
{
    MyDataContext*  data = (MyDataContext*) malloc(sizeof(MyDataContext));
    myInitializeDataContextFunction(data);
    // 創(chuàng)建隊(duì)列并設(shè)置上下文.
    dispatch_queue_t serialQueue =
    dispatch_queue_create("com.example.CriticalTaskQueue", NULL);
    if (serialQueue)
    {
        dispatch_set_context(serialQueue, data);
        dispatch_set_finalizer_f(serialQueue, &myFinalizerFunction);
    }
    return serialQueue;
}

4.5 添加任務(wù)到隊(duì)列

GCD有兩種方式來把任務(wù)添加到隊(duì)列中:異步和同步。一般情況下,使用dispatch_async和dispatch_async_f來執(zhí)行異步操作,是比同步操作更好的選擇。當(dāng)我們添加一個block對象或C函數(shù)到一個隊(duì)列中后就立即返回了,任務(wù)會在之后由 GCD 決定執(zhí)行,以及任務(wù)什么時候執(zhí)行完我們是無法知道確定的。這樣的好處是,如果我們需要在后臺執(zhí)行一個基于網(wǎng)絡(luò)或 CPU 緊張的任務(wù)時就使用異步方法 ,這樣就不會阻塞當(dāng)前線程。

盡管一般情況下,我們會優(yōu)先選擇異步操作,但是在某些情況下,我們還是需要任務(wù)同步來執(zhí)行。比如需要用同步操作來防止資源競爭或其他同步問題。這時,我們可以用 dispatch_sync和dispatch_sync_f方法來把任務(wù)添加到隊(duì)列中,這樣被添加的任務(wù)會阻塞當(dāng)前線程,直到這些任務(wù)執(zhí)行完。

代碼示例:

//代碼示例:
//異步執(zhí)行
dispatch_queue_t myCustomQueue;
myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL);
dispatch_async(myCustomQueue, ^{
    NSLog("Do some work here.");
});
//同步執(zhí)行
dispatch_sync(myCustomQueue, ^{
    NSLog("Do some more work here.");
});
NOTE:dispatch_async在不同隊(duì)列類型執(zhí)行的情況

自定義串行隊(duì)列:當(dāng)你想串行執(zhí)行后臺任務(wù)并追蹤它時就是一個好選擇。這消除了資源爭用,因?yàn)槟阒酪淮沃挥幸粋€任務(wù)在執(zhí)行。
主隊(duì)列:這是在一個并發(fā)隊(duì)列上完成任務(wù)后更新 UI 的一般選擇。
并發(fā)隊(duì)列:這是在后臺執(zhí)行非 UI 工作的一般選擇
任務(wù)執(zhí)行完后添加一個完成塊(Completion Block)

通常來說,我們把任務(wù)添加到隊(duì)列后,一旦任務(wù)執(zhí)行完,我們希望能得到通知并及時處理任務(wù)完成的結(jié)果。安裝傳統(tǒng)的異步開發(fā)流程,我們可以使用回調(diào)機(jī)制,或者在隊(duì)列中使用完成塊(Completion Block)。

一個Completion Block是在原任務(wù)完成后,我們給隊(duì)列添加的一個代碼塊。回調(diào)代碼的經(jīng)典做法一般是在任務(wù)開始時,把completion block當(dāng)成一個參數(shù)。需要我們做的只是把一個指定的block或函數(shù),在指定的隊(duì)列完成時,提交給這個隊(duì)列即可。

下面是在一個計(jì)算平均值的函數(shù),其利用了block方法來作為運(yùn)算結(jié)果的回調(diào)。這個函數(shù)的最后參數(shù)queue、block,指定了一個queue和一個block,其在計(jì)算完數(shù)值結(jié)果后會把結(jié)果值傳給這個block,然后再把block分發(fā)到這個隊(duì)列(queue)中。注意,為了避免queue被提前釋放掉了,我們可以在函數(shù)執(zhí)行開始階段為隊(duì)列retain,然后在completion block完成后再release隊(duì)列。

代碼示例:

void average_async(int *data, size_t len,
                   dispatch_queue_t queue, void (^block)(int))
{
    // Retain the queue 以此確保在completion block
    // 完成前不會被釋放掉
    dispatch_retain(queue);
    // Do the work on the default concurrent queue and then
    // call the user-provided block with the results.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                   ^{
                       int avg = average(data, len);
                       dispatch_async(queue, ^{ block(avg);});
                       // Release the queue
                       dispatch_release(queue);
                   });
}

4.6 并發(fā)執(zhí)行迭代循環(huán)

在開發(fā)中,并發(fā)隊(duì)列能很好地提高效率,特別是當(dāng)我們需要執(zhí)行一個數(shù)據(jù)龐大的循環(huán)操作時。打個比方來說吧,我們需要執(zhí)行一個for循環(huán),每一次循環(huán)操作如下:

for (i = 0; i < count; i++) {
    NSLog("%d",i);
}

GCD提供了一個簡化方法叫做dispatch_apply,當(dāng)我們把這個方法放到并發(fā)隊(duì)列中執(zhí)行時,這個函數(shù)會調(diào)用單一block多次,并平行運(yùn)算,然后等待所有運(yùn)算結(jié)束。

代碼示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(count, queue, ^(size_t i) {
    NSLog("%d",i);
});

怎么樣,是不是很棒,但是需要異步怎么辦?dispatch_apply函數(shù)是沒有異步版本的。解決的方法是只要用dispatch_async函數(shù)將所有代碼推到后臺就行了。

代碼示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
    dispatch_apply(count, queue, ^(size_t i) {
        NSLog("%d",i);
    });
});

4.7 掛起和恢復(fù)隊(duì)列

有時候,我們不想讓隊(duì)列中的某些任務(wù)馬上執(zhí)行,這時我們可以通過掛起操作來阻止一個隊(duì)列中將要執(zhí)行的任務(wù)。當(dāng)需要掛起隊(duì)列時,使用dispatch_suspend方法;恢復(fù)隊(duì)列時,使用dispatch_resume方法。調(diào)用dispatch_suspend會增加隊(duì)列掛起的引用計(jì)數(shù),而調(diào)用dispatch_resume則會減少引用計(jì)數(shù),當(dāng)引用計(jì)數(shù)大于0時,隊(duì)列會保持掛起狀態(tài)。因此,這隊(duì)列的掛起和恢復(fù)中,我們需要小心使用以避免引用計(jì)數(shù)計(jì)算錯誤的出現(xiàn)。

代碼示例:

dispatch_queue_t myQueue;
myQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL);
//掛起隊(duì)列
dispatch_suspend(myQueue);
//恢復(fù)隊(duì)列
dispatch_resume(myQueue);
NOTE:執(zhí)行掛起操作不會對已經(jīng)開始執(zhí)行的任務(wù)起作用,它僅僅只會阻止將要進(jìn)行但是還未開始的任務(wù)。

4.8 使用Dispatch Semaphores

信號量的作用是控制多個任務(wù)對有限數(shù)量資源的訪問。一個dispatch semaphore就像一個普通信號的例外。當(dāng)資源可用時,獲取dispatch semaphore的時間比獲取傳統(tǒng)的系統(tǒng)信號量要更少。這是因?yàn)镚CD不調(diào)用這個特殊情況下的內(nèi)核。唯一的一次需要在內(nèi)核中調(diào)用的情況是,當(dāng)資源不可用且系統(tǒng)需要在停止你的線程直到獲取信號。舉例來說更容易理解,如果你創(chuàng)建了一個有著兩個資源的信號量,那同時最多只能有兩個線程可以訪問臨界區(qū)。其他想使用資源的線程必須在FIFO隊(duì)列里等待。

4.9 常用的dispatch semaphore的語法:

當(dāng)創(chuàng)建信號量(使用dispatch_semaphore_create方法),我們可以指定一個正整數(shù),表示可用資源的數(shù)量。

在每一個任務(wù)里,調(diào)用dispatch_semaphore_wait來等待信號量。

當(dāng)?shù)却{(diào)用返回時,獲取資源并做自己的工作。

當(dāng)我們用到資源后,釋放掉它,然后通過調(diào)用dispatch_semaphore_signal方法來發(fā)出信號。

每一個應(yīng)用都提供了有限的文件描述符來使用,如果我們需要處理一大堆的文件時,我們不想在運(yùn)行文件描述符的時候同時打開很多文件。取而代之的是,我們可以用信號量來限制同一時間里文件描述符的數(shù)量。下面就是為了實(shí)現(xiàn)此需求的簡單

代碼:

// 創(chuàng)建一個信號量
dispatch_semaphore_t fd_sema = dispatch_semaphore_create(getdtablesize() / 2);
// 等待一個空閑的文件描述符
dispatch_semaphore_wait(fd_sema, DISPATCH_TIME_FOREVER);
fd = open("/etc/services", O_RDONLY);
// 當(dāng)完成時,釋放掉文件描述符
close(fd);
dispatch_semaphore_signal(fd_sema);

4.10 Dispatch Groups的使用

Dispatch groups是阻塞線程直到一個或多個任務(wù)完成的一種方式。在那些需要等待任務(wù)完成才能執(zhí)行某個處理的時候,你可以使用這個方法。Dispatch Group會在整個組的任務(wù)都完成時通知你,這些任務(wù)可以是同步的,也可以是異步的,即便在不同的隊(duì)列也行。而且在整個組的任務(wù)都完成時,Dispatch Group可以用同步的或者異步的方式通知你。當(dāng)group中所有的任務(wù)都完成時,GCD 提供了兩種通知方式。

dispatch_group_wait。它會阻塞當(dāng)前線程,直到組里面所有的任務(wù)都完成或者等到某個超時發(fā)生。

代碼示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
// 添加隊(duì)列到組中
dispatch_group_async(group, queue, ^{
    // 一些異步操作
});
//如果在所有任務(wù)完成前超時了,該函數(shù)會返回一個非零值。
//你可以對此返回值做條件判斷以確定是否超出等待周期;
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// 不需要group后將做釋放操作

dispatch_release(group);
dispatch_group_notify。它以異步的方式工作,當(dāng) Dispatch Group中沒有任何任務(wù)時,它就會執(zhí)行其代碼,那么 completionBlock便會運(yùn)行。

代碼示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
// 添加隊(duì)列到組中
dispatch_group_async(group, queue, ^{
    // 一些異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    if (completionBlock) { completionBlock(error); }
});

OK!以上即是GCD的一些基本用法。下一部分將是講解GCD的進(jìn)階編程,敬請期待。。。

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

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

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