GCD API記錄(二)

前言

這是關(guān)于GCD的第二篇文章晤碘,GCD的API有100多個晴及,通過快捷鍵Option + 單擊虚倒,可以在Reference中的Grand Central Dispatch (GCD) Reference中看到诊笤。除了上篇文章介紹的幾個外系谐,其他用到的API就在這篇文章里記錄。

API 匯總記錄

1.dispatch_once

Execute a block once and only once.執(zhí)行一個block一次讨跟,且僅執(zhí)行一次纪他。

利用這個API,我們可以很方便的寫單例晾匠。

static HLTestObject *instance = nil;

+(instancetype)sharedInstance{staticdispatch_once_t onceToken;? ?

dispatch_once(&onceToken, ^{instance= [[[self class] alloc] init];? ? });returninstance;}

需要注意的是instance 和onceToken一定要保證是全局變量茶袒,用static修飾是最好的方案。

完整的關(guān)于單例的寫法和注意事項可以看這里iOS中的單例你用對了么凉馆?

2.dispatch_after

Schedule a block for execution on a given queue at a specified time

在指定的queue上特殊的時間執(zhí)行某個block片段

關(guān)于dispatch_time薪寓,第一個參數(shù)通常使用DISPATCH_TIME_NOW,它是一個表示

dispatch_time_t 的宏澜共,表示從現(xiàn)在開始算起向叉,第二個參數(shù)是第一個參數(shù)之后經(jīng)歷的時長。而我們通常用的NSEC_PER_SEC也是一個宏嗦董,還有其他的宏:

#defineNSEC_PER_SEC 1000000000ull//每秒有多少納秒

#defineNSEC_PER_MSEC 1000000ull//每毫秒有多少納秒

#defineUSEC_PER_SEC 1000000ull// 每秒有多少微秒

#defineNSEC_PER_USEC 1000ull// 每微秒有多少納秒

因為1秒鐘有NSEC_PER_SEC(也即1000000000)納秒母谎,所以NSEC_PER_SEC其實就相當(dāng)于1秒,那么兩秒就是2NSEC_PER_SEC京革;

同理奇唤,

NSEC_PER_MSEC就相當(dāng)于是1毫秒,那么2秒鐘匹摇,就應(yīng)該是2000NSEC_PER_MSEC冻记;

USEC_PER_SEC也相當(dāng)于1毫秒,2秒鐘就是2000USEC_PER_SEC来惧;

NSEC_PER_USEC相當(dāng)于 1微妙冗栗,所以要表示1秒鐘就是1000000NSEC_PER_USEC。

所以1秒后執(zhí)行某段代碼可以這樣寫:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{? ? ? ? NSLog(@"哈哈");? ? });? ? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1000 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{? ? ? ? NSLog(@"嘿嘿");});dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1000* USEC_PER_SEC)), dispatch_get_main_queue(), ^{? ? ? ? NSLog(@"嗯嗯");? ? });? ? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1000000 * NSEC_PER_USEC)), dispatch_get_main_queue(), ^{? ? ? ? NSLog(@"呃呃");});

這個API的作用與下面這個方法類似:

[selfperformSelector:@selector(testClick:)withObject:nilafterDelay:2.0];

3.dispatch_group

關(guān)于dispatch_group的API有好幾個供搀,相關(guān)API的使用場景是:在多個異步任務(wù)全部執(zhí)行完畢后隅居,執(zhí)行某個任務(wù)。如果用同步任務(wù)或串行隊列葛虐,就沒有意義了胎源,要謹(jǐn)記。

這里有兩種實現(xiàn)方式:

方式一

利用dispatch_group_async和dispatch_group_notify配合屿脐,關(guān)鍵代碼:

dispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_get_global_queue(0,0);for (inti =0; i < 5; i++) {dispatch_group_async(group, queue, ^{? ? ? ? ? ? NSLog(@"并發(fā)%d----線程:%@", i,[NSThread currentThread]);[NSThread sleepForTimeInterval:i];});}? ? dispatch_group_notify(group, queue, ^{? ? ? ? NSLog(@"dispatch_group_notify---%@",[NSThread currentThread]);});// 打印結(jié)果:2016-07-0818:00:22.795PractiseProject[10437:231800] 并發(fā)0----線程:{number =2, name = (null)}2016-07-0818:00:22.795PractiseProject[10437:231815] 并發(fā)1----線程:{number =3, name = (null)}2016-07-0818:00:22.795PractiseProject[10437:231821] 并發(fā)3----線程:{number =4, name = (null)}2016-07-0818:00:22.795PractiseProject[10437:231800] 并發(fā)4----線程:{number =2, name = (null)}2016-07-0818:00:22.795PractiseProject[10437:231807] 并發(fā)2----線程:{number =5, name = (null)}2016-07-0818:00:26.799PractiseProject[10437:231821] dispatch_group_notify---{number =4, name = (null)}

方式二

利用dispatch_group_enter涕蚤、dispatch_group_leave和dispatch_group_notify配合宪卿,其中需要注意的是有dispatch_group_enter就必定有一個dispatch_group_leave與之對應(yīng),否則可能會出現(xiàn)令你意想不到的崩潰万栅。

關(guān)鍵代碼:

dispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_get_global_queue(0,0);for (inti =0; i < 5; i++) {dispatch_group_enter(group);dispatch_async(queue, ^{? ? ? ? ? ? NSLog(@"并發(fā)%d----線程:%@", i,[NSThread currentThread]);[NSThread sleepForTimeInterval:i];dispatch_group_leave(group);});}? ? dispatch_group_notify(group, queue, ^{? ? ? ? NSLog(@"dispatch_group_notify---%@",[NSThread currentThread]);});// 打印結(jié)果:2016-07-1110:57:56.697PractiseProject[1859:76390] 并行1----線程:{number =2, name = (null)}2016-07-1110:57:56.697PractiseProject[1859:76421] 并行2----線程:{number =3, name = (null)}2016-07-1110:57:56.697PractiseProject[1859:76399] 并行0----線程:{number =5, name = (null)}2016-07-1110:57:56.697PractiseProject[1859:76436] 并行3----線程:{number =4, name = (null)}2016-07-1110:57:56.697PractiseProject[1859:76437] 并行4----線程:{number =6, name = (null)}2016-07-1110:58:00.702PractiseProject[1859:76436] dispatch_group_notify---{number =4, name = (null)}

4.dispatch_barrier

dispatch_barrier分為同步dispatch_barrier_sync和異步dispatch_barrier_async兩種情況佑钾。dispatch_barrier的功能其實跟上面標(biāo)題3的場景比較類似,它可以保證在dispatch_barrier前提交的任務(wù)執(zhí)行完后烦粒,再執(zhí)行dispatch_barrier中的任務(wù)休溶,等dispatch_barrier中的任務(wù)執(zhí)行完后,才繼續(xù)執(zhí)行在dispatch_barrier之后提交的任務(wù)扰她。

4.1 dispatch_barrier_async

首先兽掰,介紹一下異步dispatch_barrier_async,它會在新線程中執(zhí)行任務(wù)徒役,在蘋果官方的描述中是這么寫的:

11.png

大致意思是:如果我們用dispatch_queue_create創(chuàng)建的并發(fā)隊列上孽尽,使用dispatch_barrier_async,那么在dispatch_barrier_async中的任務(wù)會等在它之前提交的任務(wù)全部執(zhí)行完(之前的幾個任務(wù)哪個先執(zhí)行完依然是不確定的)后再執(zhí)行,而在它之后提交的任務(wù)忧勿,會等dispatch_barrier_async中的任務(wù)執(zhí)行完之后杉女,才會開始執(zhí)行。但是如果使用串行隊列或者dispatch_get_global_queue創(chuàng)建的并發(fā)隊列狐蜕,則dispatch_barrier_async的功能就類似dispatch_async,可以將dispatch_barrier_async直接替換成dispatch_async卸夕,效果一樣层释。

一個使用dispatch_barrier_async的示例代碼:

dispatch_queue_t queue = dispatch_queue_create("com.haley.cn", DISPATCH_QUEUE_CONCURRENT);for (inti =0; i < 5; i++) {dispatch_async(queue, ^{? ? ? ? ? ? NSLog(@"并發(fā)%d----線程:%@", i,[NSThread currentThread]);[NSThread sleepForTimeInterval:i];});if (i==2) {? ? ? ? ? ? dispatch_barrier_async(queue, ^{? ? ? ? ? ? ? ? NSLog(@"barrier----%@",[NSThread currentThread]);});}? ? }// 打印結(jié)果:2016-07-1112:45:36.173PractiseProject[2579:110181] 并發(fā)2----線程:{number =3, name = (null)}2016-07-1112:45:36.173PractiseProject[2579:110175] 并發(fā)1----線程:{number =4, name = (null)}2016-07-1112:45:36.173PractiseProject[2579:110166] 并發(fā)0----線程:{number =2, name = (null)}2016-07-1112:45:38.177PractiseProject[2579:110181] barrier----{number =3, name = (null)}2016-07-1112:45:38.177PractiseProject[2579:110175] 并發(fā)4----線程:{number =4, name = (null)}2016-07-1112:45:38.177PractiseProject[2579:110181] 并發(fā)3----線程:{number =3, name = (null)}

接下來介紹dispatch_barrier_async的使用場景,我們都知道關(guān)于數(shù)據(jù)的讀寫安全是非常麻煩的,必須保證在寫入數(shù)據(jù)的時候快集,不能讀取數(shù)據(jù)贡羔;而寫入完成后,不管有多少個線程在讀取數(shù)據(jù)都是OK的个初。這個場景使用dispatch_barrier_async再合適不過了乖寒。

如何操作呢?

重寫某個數(shù)據(jù)的set 和get 方法:

- (void)setHeight:(int)height{? ? dispatch_barrier_async(_conCorrentQueue, ^{? ? ? ? _height =height;? ? });}- (int)height{? ? __blockintheight;? ? dispatch_sync(_conCorrentQueue, ^{height= _height;? ? });returnheight;}

注意:1.從Xcode 4開始院溺,我們定義property后楣嘁,編譯器會自動幫我們添加@synthesize,但是如果我們同時重寫setter和getter,那么編譯器便不再幫我們添加@synthesize珍逸,我們需要自己添加@synthesize逐虚。

2.dispatch_barrier_async只能使用dispatch_queue_create創(chuàng)建的并發(fā)隊列,才能正確發(fā)揮它的作用谆膳。

4.2 dispatch_barrier_sync

dispatch_barrier_sync與dispatch_barrier_async的功能基本一致叭爱,不同之處是,dispatch_barrier_sync是在當(dāng)前線程中執(zhí)行block中的任務(wù)漱病,而dispatch_barrier_async則是在新的線程(有可能是之前使用過的子線程)中執(zhí)行任務(wù)买雾。 它們都是在用dispatch_queue_create創(chuàng)建的并發(fā)隊列上有效果把曼,而在串行隊列或者dispatch_get_global_queue創(chuàng)建的并發(fā)隊列中,作用與dispatch_sync一致漓穿。

dispatch_queue_t queue = dispatch_queue_create("com.haley.cn", DISPATCH_QUEUE_CONCURRENT);for (inti =0; i < 5; i++) {dispatch_async(queue, ^{? ? ? ? ? ? [NSThread sleepForTimeInterval:2];NSLog(@"并發(fā)%d----線程:%@", i,[NSThread currentThread]);});if (i==2) {? ? ? ? ? ? dispatch_barrier_sync(queue, ^{? ? ? ? ? ? ? ? NSLog(@"barrier----%@",[NSThread currentThread]);});}? ? }// 打印結(jié)果:2016-07-1113:27:19.139PractiseProject[2820:122236] 并發(fā)0----線程:{number =4, name = (null)}2016-07-1113:27:19.139PractiseProject[2820:122229] 并發(fā)1----線程:{number =3, name = (null)}2016-07-1113:27:19.139PractiseProject[2820:122322] 并發(fā)2----線程:{number =2, name = (null)}2016-07-1113:27:19.140PractiseProject[2820:122192] barrier----{number =1, name = main}2016-07-1113:27:21.143PractiseProject[2820:122322] 并發(fā)4----線程:{number =2, name = (null)}2016-07-1113:27:21.143PractiseProject[2820:122229] 并發(fā)3----線程:{number =3, name = (null)}

dispatch_barrier決定的只是它的任務(wù)是否在新的線程中執(zhí)行嗤军,以及它一定在前面幾個任務(wù)執(zhí)行完后執(zhí)行,并不會影響之前任務(wù)的執(zhí)行順序等器净。

在串行隊列或者dispatch_get_global_queue創(chuàng)建的并發(fā)隊列中型雳,dispatch_barrier_sync僅僅相當(dāng)于dispatch_sync。

5.Queue-Specific

由于dispatch_get_current_queueAPI的移除山害,為了能夠判斷當(dāng)前queue是否是之前創(chuàng)建的queue纠俭,我們可以利用dispatch_queue_set_specific和dispatch_get_specific給queue關(guān)聯(lián)一個context data,后面再利用這個標(biāo)識獲取到context data浪慌。如果可以獲取到說明當(dāng)前上下文是在自己創(chuàng)建的queue中冤荆,如果不能獲取到context data則表示當(dāng)前是在其他隊列上。

使用場景: 自己創(chuàng)建一個隊列权纤,然后保證所有的操作都在該隊列上執(zhí)行钓简。XMPP中有比較多的dispatch_queue_set_specific和dispatch_get_specific使用案例。

設(shè)置標(biāo)識和關(guān)聯(lián)的數(shù)據(jù):

dispatch_queue_tqueue= dispatch_queue_create("com.haley.cn", DISPATCH_QUEUE_SERIAL);constvoid*queueSpecificKey = @"queueSpecificKey";dispatch_queue_set_specific(queue, queueSpecificKey, &queueSpecificKey,NULL);

獲取關(guān)聯(lián)數(shù)據(jù):dispatch_get_specific(queueSpecificKey)

完整的示例:

dispatch_queue_tqueue = dispatch_queue_create("com.haley.cn", DISPATCH_QUEUE_SERIAL);// 當(dāng)然這里也可以是其他類型的隊列//? ? dispatch_queue_t queue = dispatch_get_global_queue(0, 0);//? ? dispatch_queue_t queue = dispatch_queue_create("com.haley.cn", DISPATCH_QUEUE_CONCURRENT);constvoid*queueSpecificKey =@"queueSpecificKey";? ? dispatch_queue_set_specific(queue, queueSpecificKey, &queueSpecificKey,NULL);dispatch_async(queue, ^{NSLog(@"異步任務(wù)");if(dispatch_get_specific(queueSpecificKey)) {NSLog(@"com.haley.cn---1隊列");? ? ? ? }else{NSLog(@"---1其他隊列");? ? ? ? }? ? });NSLog(@"主線程汹想,主隊列");if(dispatch_get_specific(queueSpecificKey)) {NSLog(@"com.haley.cn---2隊列");? ? }else{NSLog(@"----2其他隊列");? ? }// 打印結(jié)果:2016-07-1114:30:56.772PractiseProject[3379:152363] 主線程外邓,主隊列2016-07-1114:30:56.772PractiseProject[3379:152363] ----2其他隊列2016-07-1114:30:56.772PractiseProject[3379:152451] 異步任務(wù)2016-07-1114:30:56.773PractiseProject[3379:152451] com.haley.cn---1隊列

dispatch_get_specific所處的環(huán)境如果是在目標(biāo)對列上時,就可以獲取到關(guān)聯(lián)的數(shù)據(jù)古掏,否則就無法獲取關(guān)聯(lián)數(shù)據(jù)损话,返回NULL。

看一看XMPP中的使用案例:

- (BOOL)activate:(XMPPStream*)aXmppStream{ __blockBOOLresult = YES;dispatch_block_tblock= ^{? if (xmppStream != nil)? {? result = NO;}? else? {? xmppStream = aXmppStream;[xmppStreamaddDelegate:selfdelegateQueue:moduleQueue];[xmppStream registerModule:self];} };if (dispatch_get_specific(moduleQueueTag))block();elsedispatch_sync(moduleQueue,block);return result;}

為了保證block是在目標(biāo)隊列上執(zhí)行槽唾,先判斷當(dāng)前是否在目標(biāo)隊列上(如果能取到關(guān)聯(lián)數(shù)據(jù)丧枪,則說明在當(dāng)前隊列上),如果在目標(biāo)隊列上庞萍,直接執(zhí)行block拧烦,否則就在目標(biāo)隊列上同步執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钝计,一起剝皮案震驚了整個濱河市恋博,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌私恬,老刑警劉巖交播,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異践付,居然都是意外死亡秦士,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門永高,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隧土,“玉大人提针,你說我怎么就攤上這事〔芸” “怎么了辐脖?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長皆愉。 經(jīng)常有香客問我嗜价,道長,這世上最難降的妖魔是什么幕庐? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任久锥,我火速辦了婚禮,結(jié)果婚禮上异剥,老公的妹妹穿的比我還像新娘瑟由。我一直安慰自己,他們只是感情好冤寿,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布歹苦。 她就那樣靜靜地躺著,像睡著了一般督怜。 火紅的嫁衣襯著肌膚如雪殴瘦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天号杠,我揣著相機與錄音蚪腋,去河邊找鬼。 笑死究流,一個胖子當(dāng)著我的面吹牛辣吃,可吹牛的內(nèi)容都是我干的动遭。 我是一名探鬼主播芬探,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厘惦!你這毒婦竟也來了偷仿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤宵蕉,失蹤者是張志新(化名)和其女友劉穎酝静,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羡玛,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡别智,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了稼稿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薄榛。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡讳窟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敞恋,到底是詐尸還是另有隱情丽啡,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布硬猫,位于F島的核電站补箍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啸蜜。R本人自食惡果不足惜坑雅,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盔性。 院中可真熱鬧霞丧,春花似錦、人聲如沸冕香。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悉尾。三九已至突那,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間构眯,已是汗流浹背愕难。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惫霸,地道東北人猫缭。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像壹店,于是被迫代替她去往敵國和親猜丹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容