iOS中GCD的使用小結(jié)

iOS中GCD的使用小結(jié)

作者dullgrass

2015.11.20 09:41*字?jǐn)?shù) 4996閱讀 20199評(píng)論 33喜歡 192

本篇博客共分以下幾個(gè)模塊來介紹GCD的相關(guān)內(nèi)容:

多線程相關(guān)概念

多線程編程技術(shù)的優(yōu)缺點(diǎn)比較?

GCD中的三種隊(duì)列類型

The main queue(主線程串行隊(duì)列)

Global queue(全局并發(fā)隊(duì)列)

Custom queue (自定義隊(duì)列)

Group queue (隊(duì)列組)

GCD中一些系統(tǒng)提供的常用dispatch方法

歡迎訪問作者個(gè)人博客www.dullgrass.com,更多好的文章與您分享

多線程相關(guān)概念

進(jìn)程與線程

進(jìn)程概念: 進(jìn)程是程序在計(jì)算機(jī)上的一次執(zhí)行活動(dòng),打開一個(gè)app,就開啟了一個(gè)進(jìn)程,可包含多個(gè)線程。

線程概念: 獨(dú)立執(zhí)行的代碼段,一個(gè)線程同時(shí)間只能執(zhí)行一個(gè)任務(wù),反之多線程并發(fā)就可以在同一時(shí)間執(zhí)行多個(gè)任務(wù)。

iOS程序中,主線程(又叫作UI線程)主要任務(wù)是處理UI事件,顯示和刷新UI,(只有主線程有直接修改UI的能力)耗時(shí)的操作放在子線程(又叫作后臺(tái)線程、異步線程)。在iOS中開子線程去處理耗時(shí)的操作,可以有效提高程序的執(zhí)行效率,提高資源利用率。但是開啟線程會(huì)占用一定的內(nèi)存,(主線程的堆棧大小是1M,第二個(gè)線程開始都是512KB,并且該值不能通過編譯器開關(guān)或線程API函數(shù)來更改)降低程序的性能。所以一般不要同時(shí)開很多線程。

線程相關(guān)

同步線程:同步線程會(huì)阻塞當(dāng)前線程去執(zhí)行線程內(nèi)的任務(wù),執(zhí)行完之后才會(huì)反回當(dāng)前線程。

異步線程:異步線程不會(huì)阻塞當(dāng)前線程,會(huì)開啟其他線程去執(zhí)行線程內(nèi)的任務(wù)。

串行隊(duì)列:線程任務(wù)按先后順序逐個(gè)執(zhí)行(需要等待隊(duì)列里面前面的任務(wù)執(zhí)行完之后再執(zhí)行新的任務(wù))。

并發(fā)隊(duì)列:多個(gè)任務(wù)按添加順序一起開始執(zhí)行(不用等待前面的任務(wù)執(zhí)行完再執(zhí)行新的任務(wù)),但是添加間隔往往忽略不計(jì),所以看著像是一起執(zhí)行的。

并發(fā)VS并行:并行是基于多核設(shè)備的,并行一定是并發(fā),并發(fā)不一定是并行。

多線程中會(huì)出現(xiàn)的問題

Critical Section(臨界代碼段)

指的是不能同時(shí)被兩個(gè)線程訪問的代碼段,比如一個(gè)變量,被并發(fā)進(jìn)程訪問后可能會(huì)改變變量值,造成數(shù)據(jù)污染(數(shù)據(jù)共享問題)。

Race Condition (競(jìng)態(tài)條件)

當(dāng)多個(gè)線程同時(shí)訪問共享的數(shù)據(jù)時(shí),會(huì)發(fā)生爭(zhēng)用情形,第一個(gè)線程讀取改變了一個(gè)變量的值,第二個(gè)線程也讀取改變了這個(gè)變量的值,兩個(gè)線程同時(shí)操作了該變量,此時(shí)他們會(huì)發(fā)生競(jìng)爭(zhēng)來看哪個(gè)線程會(huì)最后寫入這個(gè)變量,最后被寫入的值將會(huì)被保留下來。

Deadlock (死鎖)

兩個(gè)(多個(gè))線程都要等待對(duì)方完成某個(gè)操作才能進(jìn)行下一步,這時(shí)就會(huì)發(fā)生死鎖。

Thread Safe(線程安全)

一段線程安全的代碼(對(duì)象),可以同時(shí)被多個(gè)線程或并發(fā)的任務(wù)調(diào)度,不會(huì)產(chǎn)生問題,非線程安全的只能按次序被訪問。

所有Mutable對(duì)象都是非線程安全的,所有Immutable對(duì)象都是線程安全的,使用Mutable對(duì)象,一定要用同步鎖來同步訪問(@synchronized)。

互斥鎖:能夠防止多線程搶奪造成的數(shù)據(jù)安全問題,但是需要消耗大量的資源

原子屬性(atomic)加鎖

atomic: 原子屬性,為setter方法加鎖,將屬性以atomic的形式來聲明,該屬性變量就能支持互斥鎖了。

nonatomic: 非原子屬性,不會(huì)為setter方法加鎖,聲明為該屬性的變量,客戶端應(yīng)盡量避免多線程爭(zhēng)奪同一資源。

Context Switch (上下文切換)

當(dāng)一個(gè)進(jìn)程中有多個(gè)線程來回切換時(shí),context switch用來記錄執(zhí)行狀態(tài),這樣的進(jìn)程和一般的多線程進(jìn)程沒有太大差別,但會(huì)產(chǎn)生一些額外的開銷。

多線程編程技術(shù)的優(yōu)缺點(diǎn)比較

NSThread (抽象層次:低)

優(yōu)點(diǎn):輕量級(jí),簡(jiǎn)單易用,可以直接操作線程對(duì)象

缺點(diǎn): 需要自己管理線程的生命周期,線程同步。線程同步對(duì)數(shù)據(jù)的加鎖會(huì)有一定的系統(tǒng)開銷。

Cocoa NSOperation? (抽象層次:中)

優(yōu)點(diǎn):不需要關(guān)心線程管理,數(shù)據(jù)同步的事情,可以把精力放在學(xué)要執(zhí)行的操作上。基于GCD,是對(duì)GCD 的封裝,比GCD更加面向?qū)ο?/p>

缺點(diǎn): NSOperation是個(gè)抽象類,使用它必須使用它的子類,可以實(shí)現(xiàn)它或者使用它定義好的兩個(gè)子類NSInvocationOperation、NSBlockOperation.

GCD 全稱Grand Center Dispatch (抽象層次:高)

優(yōu)點(diǎn):是 Apple 開發(fā)的一個(gè)多核編程的解決方法,簡(jiǎn)單易用,效率高,速度快,基于C語言,更底層更高效,并且不是Cocoa框架的一部分,自動(dòng)管理線程生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)。

缺點(diǎn): 使用GCD的場(chǎng)景如果很復(fù)雜,就有非常大的可能遇到死鎖問題。

GCD抽象層次最高,使用也簡(jiǎn)單,因此,蘋果也推薦使用GCD

GCD中的三種隊(duì)列類型

GCD編程的核心就是dispatch隊(duì)列,dispatch block的執(zhí)行最終都會(huì)放進(jìn)某個(gè)隊(duì)列中去進(jìn)行。

The main queue(主線程串行隊(duì)列): 與主線程功能相同,提交至Main queue的任務(wù)會(huì)在主線程中執(zhí)行,

Main queue 可以通過dispatch_get_main_queue()來獲取。

Global queue(全局并發(fā)隊(duì)列): 全局并發(fā)隊(duì)列由整個(gè)進(jìn)程共享,有高、中(默認(rèn))、低、后臺(tái)四個(gè)優(yōu)先級(jí)別。

Global queue 可以通過調(diào)用dispatch_get_global_queue函數(shù)來獲?。梢栽O(shè)置優(yōu)先級(jí))

Custom queue (自定義隊(duì)列): 可以為串行,也可以為并發(fā)。

Custom queue 可以通過dispatch_queue_create()來獲??;

Group queue (隊(duì)列組):將多線程進(jìn)行分組,最大的好處是可獲知所有線程的完成情況。

Group queue 可以通過調(diào)用dispatch_group_create()來獲取,通過dispatch_group_notify,可以直接監(jiān)聽組里所有線程完成情況。

gcd中相關(guān)函數(shù)的使用一般都是以dispatch開頭

The main queue(主線程串行隊(duì)列)

dispatch_sync 同步執(zhí)行任務(wù)函數(shù),不會(huì)開啟新的線程,dispatch_async 異步執(zhí)行任務(wù)函數(shù),會(huì)開啟新的線程

獲取主線程串行隊(duì)列

dispatch_queue_tmainQueue = dispatch_get_main_queue();

主線程串行隊(duì)列同步執(zhí)行任務(wù),在主線程運(yùn)行時(shí),會(huì)產(chǎn)生死鎖

dispatch_queue_tmainQueue = dispatch_get_main_queue();dispatch_sync(mainQueue,^{NSLog("MainQueue");? ? ? ? ? ? });

程序一直處于等待狀態(tài),block中的代碼將執(zhí)行不到

主線程串行隊(duì)列異步執(zhí)行任務(wù),在主線程運(yùn)行,不會(huì)產(chǎn)生死鎖。

dispatch_queue_tmainQueue = dispatch_get_main_queue();dispatch_async(mainQueue,^{NSLog("MainQueue");? ? ? ? ? ? });

程序正常運(yùn)行,block中的代碼正常運(yùn)行

從子線程,異步返回主線程更新UI<這種使用方式比較多>

dispatch_queue_tglobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);dispatch_async(globalQueue, ^{//子線程異步執(zhí)行下載任務(wù),防止主線程卡頓NSURL*url = [NSURLURLWithString:@"http://www.baidu.com"];NSError*error;NSString*htmlData = [NSStringstringWithContentsOfURL:url encoding:NSUTF8StringEncodingerror:&error];if(htmlData !=nil) {dispatch_queue_tmainQueue = dispatch_get_main_queue();//異步返回主線程,根據(jù)獲取的數(shù)據(jù),更新UIdispatch_async(mainQueue, ^{NSLog(@"根據(jù)更新UI界面");? ? ? ? });? ? }else{NSLog(@"error when download:%@",error);? ? }});

主線程串行隊(duì)列由系統(tǒng)默認(rèn)生成的,所以無法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷。

Global queue(全局并發(fā)隊(duì)列)

耗時(shí)的操作,比如讀取網(wǎng)絡(luò)數(shù)據(jù),IO,數(shù)據(jù)庫(kù)讀寫等,我們會(huì)在另外一個(gè)線程中處理這些操作,然后通知主線程更新界面

獲取全局并發(fā)隊(duì)列

//程序默認(rèn)的隊(duì)列級(jí)別,一般不要修改,DISPATCH_QUEUE_PRIORITY_DEFAULT == 0dispatch_queue_tglobalQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//HIGHdispatch_queue_tglobalQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);//LOWdispatch_queue_tglobalQueue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);//BACKGROUNDdispatch_queue_tglobalQueue4 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);

全局并發(fā)隊(duì)列同步執(zhí)行任務(wù),在主線程執(zhí)行會(huì)導(dǎo)致頁(yè)面卡頓。

dispatch_queue_tglobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);NSLog(@"current task");dispatch_sync(globalQueue, ^{? ? sleep(2.0);NSLog(@"sleep 2.0s");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1815:51:45.550Whisper[33152:345023] current task2015-11-1815:51:47.552Whisper[33152:345023] sleep2.0s2015-11-1815:51:47.552Whisper[33152:345023] next task

2s鐘之后,才會(huì)執(zhí)行block代碼段下面的代碼。

全局并發(fā)隊(duì)列異步執(zhí)行任務(wù),在主線程運(yùn)行,會(huì)開啟新的子線程去執(zhí)行任務(wù),頁(yè)面不會(huì)卡頓。

dispatch_queue_tglobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);NSLog(@"current task");dispatch_async(globalQueue, ^{? ? sleep(2.0);NSLog(@"sleep 2.0s");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1815:50:14.999Whisper[33073:343781] current task2015-11-1815:50:15.000Whisper[33073:343781] next task2015-11-1815:50:17.004Whisper[33073:343841] sleep2.0s

主線程不用等待2s鐘,繼續(xù)執(zhí)行block代碼段后面的代碼。

多個(gè)全局并發(fā)隊(duì)列,異步執(zhí)行任務(wù)。

dispatch_queue_tglobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);NSLog(@"current task");dispatch_async(globalQueue, ^{NSLog(@"最先加入全局并發(fā)隊(duì)列");});dispatch_async(globalQueue, ^{NSLog(@"次加入全局并發(fā)隊(duì)列");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1816:54:52.202Whisper[39827:403208] current task2015-11-1816:54:52.203Whisper[39827:403208] next task2015-11-1816:54:52.205Whisper[39827:403309] 最先加入全局并發(fā)隊(duì)列2015-11-1816:54:52.205Whisper[39827:403291] 次加入全局并發(fā)隊(duì)列

異步線程的執(zhí)行順序是不確定的。幾乎同步開始執(zhí)行

全局并發(fā)隊(duì)列由系統(tǒng)默認(rèn)生成的,所以無法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷。

Custom queue (自定義隊(duì)列)

自定義串行隊(duì)列

獲取自定義串行隊(duì)列

dispatch_queue_tserialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);NSLog(@"%s",dispatch_queue_get_label(conCurrentQueue)) ;

控制臺(tái)輸出:

2015-11-1911:05:34.469Whisper[1223:42960] com.dullgrass.serialQueue

dispatch_queue_create(const char *label, dispatch_queue_attr_t

attr)函數(shù)中第一個(gè)參數(shù)是給這個(gè)queue起的標(biāo)識(shí),這個(gè)在調(diào)試的可以看到是哪個(gè)隊(duì)列在執(zhí)行,或者在crash日志中,也能做為提示。第二個(gè)是需要?jiǎng)?chuàng)建的隊(duì)列類型,是串行的還是并發(fā)的

自定義串行隊(duì)列同步執(zhí)行任務(wù)

dispatch_queue_tserialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);NSLog(@"current task");dispatch_sync(serialQueue, ^{NSLog(@"最先加入自定義串行隊(duì)列");sleep(2);});dispatch_sync(serialQueue, ^{NSLog(@"次加入自定義串行隊(duì)列");});NSLog(@"next task");

控制臺(tái)輸出:

2015-11-1817:09:40.025Whisper[40241:416296] current task2015-11-1817:09:40.027Whisper[40241:416296] 最先加入自定義串行隊(duì)列2015-11-1817:09:43.027Whisper[40241:416296] 次加入自定義串行隊(duì)列2015-11-1817:09:43.027Whisper[40241:416296] next task

當(dāng)前線程等待串行隊(duì)列中的子線程執(zhí)行完成之后再執(zhí)行,串行隊(duì)列中先進(jìn)來的子線程先執(zhí)行任務(wù),執(zhí)行完成后,再執(zhí)行隊(duì)列中后面的任務(wù)。

自定義串行隊(duì)列嵌套執(zhí)行同步任務(wù),產(chǎn)生死鎖

dispatch_queue_tserialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);dispatch_sync(serialQueue, ^{//該代碼段后面的代碼都不會(huì)執(zhí)行,程序被鎖定在這里NSLog(@"會(huì)執(zhí)行的代碼");dispatch_sync(serialQueue, ^{NSLog(@"代碼不執(zhí)行");});});

異步執(zhí)行串行隊(duì)列,嵌套同步執(zhí)行串行隊(duì)列,同步執(zhí)行的串行隊(duì)列中的任務(wù)將不會(huì)被執(zhí)行,其他程序正常執(zhí)行

dispatch_queue_tserialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);dispatch_async(serialQueue, ^{NSLog(@"會(huì)執(zhí)行的代碼");dispatch_sync(serialQueue, ^{NSLog(@"代碼不執(zhí)行");});});

注意不要嵌套使用同步執(zhí)行的串行隊(duì)列任務(wù)

自定義并發(fā)隊(duì)列

獲取自定義并發(fā)隊(duì)列

dispatch_queue_tconCurrentQueue =? dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);

自定義并發(fā)隊(duì)列執(zhí)行同步任務(wù)

dispatch_queue_tconCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_sync(conCurrentQueue, ^{NSLog(@"先加入隊(duì)列");});dispatch_sync(conCurrentQueue, ^{NSLog(@"次加入隊(duì)列");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1910:36:23.259Whisper[827:20596] current task2015-11-1910:36:23.261Whisper[827:20596] 先加入隊(duì)列2015-11-1910:36:23.261Whisper[827:20596] 次加入隊(duì)列2015-11-1910:36:23.261Whisper[827:20596] next task

自定義并發(fā)隊(duì)列嵌套執(zhí)行同步任務(wù)(不會(huì)產(chǎn)生死鎖,程序正常運(yùn)行)

dispatch_queue_tconCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_sync(conCurrentQueue, ^{NSLog(@"先加入隊(duì)列");dispatch_sync(conCurrentQueue, ^{NSLog(@"次加入隊(duì)列");? ? });});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1910:39:21.301Whisper[898:22273] current task2015-11-1910:39:21.303Whisper[898:22273] 先加入隊(duì)列2015-11-1910:39:21.303Whisper[898:22273] 次加入隊(duì)列2015-11-1910:39:21.303Whisper[898:22273] next task

自定義并發(fā)隊(duì)列執(zhí)行異步任務(wù)

dispatch_queue_tconCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);NSLog(@"current task");dispatch_async(conCurrentQueue, ^{NSLog(@"先加入隊(duì)列");});dispatch_async(conCurrentQueue, ^{NSLog(@"次加入隊(duì)列");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1910:45:22.290Whisper[1050:26445] current task2015-11-1910:45:22.290Whisper[1050:26445] next task2015-11-1910:45:22.290Whisper[1050:26505] 次加入隊(duì)列2015-11-1910:45:22.290Whisper[1050:26500] 先加入隊(duì)列

異步執(zhí)行任務(wù),開啟新的子線程,不影響當(dāng)前線程任務(wù)的執(zhí)行,并發(fā)隊(duì)列中的任務(wù),幾乎是同步執(zhí)行的,輸出順序不確定

Group queue (隊(duì)列組)

當(dāng)遇到需要執(zhí)行多個(gè)線程并發(fā)執(zhí)行,然后等多個(gè)線程都結(jié)束之后,再匯總執(zhí)行結(jié)果時(shí)可以用group queue

使用場(chǎng)景: 同時(shí)下載多個(gè)圖片,所有圖片下載完成之后去更新UI(需要回到主線程)或者去處理其他任務(wù)(可以是其他線程隊(duì)列)。

原理:使用函數(shù)dispatch_group_create創(chuàng)建dispatch

group,然后使用函數(shù)dispatch_group_async來將要執(zhí)行的block任務(wù)提交到一個(gè)dispatch

queue。同時(shí)將他們添加到一個(gè)組,等要執(zhí)行的block任務(wù)全部執(zhí)行完成之后,使用dispatch_group_notify函數(shù)接收完成時(shí)的消息。

使用示例:

dispatch_queue_tconCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);dispatch_queue_tmainQueue = dispatch_get_main_queue();dispatch_group_t groupQueue = dispatch_group_create();NSLog(@"current task");dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{NSLog(@"并行任務(wù)1");});dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{NSLog(@"并行任務(wù)2");});dispatch_group_notify(groupQueue, mainQueue, ^{NSLog(@"groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI");});NSLog(@"next task");

控制臺(tái)輸出:

2015-11-1913:47:55.117Whisper[1645:97116] current task2015-11-1913:47:55.117Whisper[1645:97116] next task2015-11-1913:47:55.119Whisper[1645:97178] 并行任務(wù)12015-11-1913:47:55.119Whisper[1645:97227] 并行任務(wù)22015-11-1913:47:55.171Whisper[1645:97116] groupQueue中的任務(wù) 都執(zhí)行完成,回到主線程更新UI

在當(dāng)前線程阻塞的同步等待dispatch_group_wait

dispatch_group_t groupQueue = dispatch_group_create();dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW,10*NSEC_PER_SEC);dispatch_queue_tconCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);NSLog(@"current task");dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{longisExecuteOver = dispatch_group_wait(groupQueue, delayTime);if(isExecuteOver) {NSLog(@"wait over");? }else{NSLog(@"not over");? }NSLog(@"并行任務(wù)1");});dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{NSLog(@"并行任務(wù)2");});

控制臺(tái)輸出如下:

2015-11-1914:37:29.514Whisper[2426:126683] current task2015-11-1914:37:29.518Whisper[2426:126791] 并行任務(wù)22015-11-1914:37:39.515Whisper[2426:126733] wait over2015-11-1914:37:39.516Whisper[2426:126733] 并行任務(wù)1

dispatch_time(dispatch_time_t when, int64_t delta);

參數(shù)注釋:

第一個(gè)參數(shù)一般是DISPATCH_TIME_NOW,表示從現(xiàn)在開始

第二個(gè)參數(shù)是延時(shí)的具體時(shí)間

延時(shí)1秒可以寫成如下幾種:

NSEC_PER_SEC----每秒有多少納秒

dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC);

USEC_PER_SEC----每秒有多少毫秒(注意是指在納秒的基礎(chǔ)上)

dispatch_time(DISPATCH_TIME_NOW, 1000*USEC_PER_SEC); //SEC---毫秒

NSEC_PER_USEC----每毫秒有多少納秒。

dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC*NSEC_PER_USEC);SEC---納秒

GCD中一些系統(tǒng)提供的常用dispatch方法

dispatch_after延時(shí)添加到隊(duì)列

使用示例:

dispatch_time_t delayTime3 = dispatch_time(DISPATCH_TIME_NOW,3*NSEC_PER_SEC);dispatch_time_t delayTime2 = dispatch_time(DISPATCH_TIME_NOW,2*NSEC_PER_SEC);dispatch_queue_tmainQueue = dispatch_get_main_queue();NSLog(@"current task");dispatch_after(delayTime3, mainQueue, ^{NSLog(@"3秒之后添加到隊(duì)列");});dispatch_after(delayTime2, mainQueue, ^{NSLog(@"2秒之后添加到隊(duì)列");});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1915:50:19.369Whisper[2725:172593] current task2015-11-1915:50:19.370Whisper[2725:172593] next task2015-11-1915:50:21.369Whisper[2725:172593]2秒之后添加到隊(duì)列2015-11-1915:50:22.654Whisper[2725:172593]3秒之后添加到隊(duì)列

dispatch_after只是延時(shí)提交block,并不是延時(shí)后立即執(zhí)行,并不能做到精確控制,需要精確控制的朋友慎用哦

dispatch_apply在給定的隊(duì)列上多次執(zhí)行某一任務(wù),在主線程直接調(diào)用會(huì)阻塞主線程去執(zhí)行block中的任務(wù)。

dispatch_apply函數(shù)的功能:把一項(xiàng)任務(wù)提交到隊(duì)列中多次執(zhí)行,隊(duì)列可以是串行也可以是并行,dispatch_apply不會(huì)立刻返回,在執(zhí)行完block中的任務(wù)后才會(huì)返回,是同步執(zhí)行的函數(shù)。

dispatch_apply正確使用方法:為了不阻塞主線程,一般把dispatch_apply放在異步隊(duì)列中調(diào)用,然后執(zhí)行完成后通知主線程

使用示例:

dispatch_queue_tglobalQueue = dispatch_get_global_queue(0,0);NSLog(@"current task");dispatch_async(globalQueue, ^{dispatch_queue_tapplyQueue = dispatch_get_global_queue(0,0);//第一個(gè)參數(shù),3--block執(zhí)行的次數(shù)//第二個(gè)參數(shù),applyQueue--block任務(wù)提交到的隊(duì)列//第三個(gè)參數(shù),block--需要重復(fù)執(zhí)行的任務(wù)dispatch_apply(3, applyQueue, ^(size_t index) {NSLog(@"current index %@",@(index));? ? ? sleep(1);});NSLog(@"dispatch_apply 執(zhí)行完成");dispatch_queue_tmainQueue = dispatch_get_main_queue();dispatch_async(mainQueue, ^{NSLog(@"回到主線程更新UI");});});NSLog(@"next task");

控制臺(tái)輸出如下:

2015-11-1916:24:45.015Whisper[4034:202269] current task2015-11-1916:24:45.016Whisper[4034:202269] next task2015-11-1916:24:45.016Whisper[4034:202347] current index02015-11-1916:24:45.016Whisper[4034:202344] current index12015-11-1916:24:45.016Whisper[4034:202345] current index22015-11-1916:24:46.021Whisper[4034:202347] dispatch_apply 執(zhí)行完成2015-11-1916:24:46.021Whisper[4034:202269] 回到主線程更新UI

嵌套使用dispatch_apply會(huì)導(dǎo)致死鎖。

dispatch_once保證在app運(yùn)行期間,block中的代碼只執(zhí)行一次

經(jīng)典使用場(chǎng)景---單例

單例對(duì)象ShareManager的定義:

ShareManager的.h文件#import@interfaceShareManager:NSObject@property(nonatomic,copy)NSString*someProperty;+ (ShareManager *)shareManager;+ (ShareManager *)sharedManager;@endShareManager的.m文件#import"ShareManager.h"@implementationShareManagerstaticShareManager *sharedManager =nil;//GCD實(shí)現(xiàn)單例功能+ (ShareManager *)shareManager{staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{? ? sharedManager = [[selfalloc] init]; });returnsharedManager;}//在ARC下,非GCD,實(shí)現(xiàn)單例功能+ (ShareManager *)sharedManager{@synchronized(self) {if(!sharedManager) {? ? ? ? sharedManager = [[selfalloc] init];? ? } }returnsharedManager;}- (instancetype)init{self= [superinit];if(self) {? ? ? _someProperty =@"Default Property Value"; }returnself;}@endShareManager的使用#import"ShareManager.h"在需要使用的函數(shù)中,直接調(diào)用下面的方法ShareManager *share = [ShareManager sharedManager];NSLog(@"share is %@",share.someProperty);

dispatch_barrier_async 柵欄的作用

功能:是在并行隊(duì)列中,等待在dispatch_barrier_async之前加入的隊(duì)列全部執(zhí)行完成之后(這些任務(wù)是并發(fā)執(zhí)行的)再執(zhí)行dispatch_barrier_async中的任務(wù),dispatch_barrier_async中的任務(wù)執(zhí)行完成之后,再去執(zhí)行在dispatch_barrier_async之后加入到隊(duì)列中的任務(wù)(這些任務(wù)是并發(fā)執(zhí)行的)。

使用示例:

dispatch_queue_tconCurrentQueue = dispatch_queue_create("com.dullgrass.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(conCurrentQueue, ^{NSLog(@"dispatch 1");});dispatch_async(conCurrentQueue, ^{NSLog(@"dispatch 2");});dispatch_barrier_async(conCurrentQueue, ^{NSLog(@"dispatch barrier");});dispatch_async(conCurrentQueue, ^{NSLog(@"dispatch 3");});dispatch_async(conCurrentQueue, ^{NSLog(@"dispatch 4");});

控制臺(tái)輸出如下:

2015-11-1918:12:34.125Whisper[22633:297257] dispatch12015-11-1918:12:34.125Whisper[22633:297258] dispatch22015-11-1918:12:34.126Whisper[22633:297258] dispatch barrier2015-11-1918:12:34.127Whisper[22633:297258] dispatch32015-11-1918:12:34.127Whisper[22633:297257] dispatch4

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

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

  • 本篇博客共分以下幾個(gè)模塊來介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較? GCD中的三種隊(duì)列...
    dullgrass閱讀 38,101評(píng)論 28 236
  • 本篇博客共分以下幾個(gè)模塊來介紹GCD的相關(guān)內(nèi)容: 多線程相關(guān)概念 多線程編程技術(shù)的優(yōu)缺點(diǎn)比較? GCD中的三種隊(duì)列...
    有夢(mèng)想的老伯伯閱讀 1,084評(píng)論 0 4
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時(shí)候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,380評(píng)論 21 42
  • GCD筆記 總結(jié)一下多線程部分,最強(qiáng)大的無疑是GCD,那么先從這一塊部分講起. Dispatch Queue的種類...
    jins_1990閱讀 833評(píng)論 0 1
  • 今天是暑假的倒數(shù)第二天了,后天就要開學(xué)了,我很激動(dòng),因?yàn)槲荫R上就要見到我思念的老師和同學(xué)們了! ...
    Greybear_閱讀 471評(píng)論 0 1

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