GCD與多個網(wǎng)絡(luò)請求的battle

在開發(fā)中畏腕,經(jīng)常會碰到這樣的情況:
1.同一個頁面上,有好幾個網(wǎng)絡(luò)請求,需要等到所有的網(wǎng)絡(luò)請求都調(diào)用結(jié)束再進行下一步操作温艇。
2.同一個頁面上逻恐,有好幾個網(wǎng)絡(luò)請求像吻,但第二個接口依賴于第一個接口,必須等到第二個調(diào)用完再調(diào)用复隆。

處理上述問題的方式很多拨匆,可以在接口回調(diào)里再去調(diào)下一個接口;可以自己加變量來判斷調(diào)用順序挽拂。但其實GCD已經(jīng)提供了很好的方法來解決這一問題惭每,可以用dispatch_group_asyncdispatch_semaphore_t來操作,具體看一下實例亏栈。

多個請求都結(jié)束再執(zhí)行下一步

使用dispatch_group_async

    //mainthread

    dispatch_group_t group = dispatch_group_create();
    NSLog(@"!-----1");
    dispatch_group_enter(group);
    [[NetworkMgr sharedMgr] refreshServerAppConfigWithCompleteHandle:^{//main thread block
        NSLog(@"!-----2");
        dispatch_group_leave(group);
    }];
    NSLog(@"!-----3");
    dispatch_group_enter(group);
    [[NetworkMgr sharedMgr] refreshBussinessRouterWithCompleteHandle:^{//main thread block
        NSLog(@"!-----4");
        dispatch_group_leave(group);
    }];
    NSLog(@"!-----5");
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"!-----6");
        if (self.homeAction) {
            self.homeAction(0, nil);
        }
    });

執(zhí)行順序

[37063:6826480] !-----1
[37063:6826480] !-----3
[37063:6826480] !-----5
[37063:6826480] !-----2
[37063:6826480] !-----4
[37063:6826480] !-----6

在執(zhí)行每一個網(wǎng)絡(luò)請求之前台腥,先dispatch_group_enter,在請求回調(diào)時绒北,再dispatch_group_leave黎侈,當兩組請求都結(jié)束后,會自動觸發(fā)dispatch_group_notify闷游,實現(xiàn)self.homeAction在兩個請求之后再調(diào)用蜓竹。

使用dispatch_semaphore_t

    NSLog(@"!-----1");
    
    dispatch_semaphore_t semphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    [[NetworkMgr sharedMgr] refreshServerAppConfigWithCompleteHandle:^{//main thread block
        NSLog(@"!-----2");
        dispatch_semaphore_signal(semphore);
    }];
    NSLog(@"!-----3");
    [[NetworkMgr sharedMgr] refreshBussinessRouterWithCompleteHandle:^{//main thread block
        NSLog(@"!-----4");
        dispatch_semaphore_signal(semphore);
    }];

    NSLog(@"!-----5");
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
        NSLog(@"!-----6");
        if (self.homeAction) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.homeAction(0, nil);
            });
        }
    });

執(zhí)行順序

[36999:6817621] !-----1
[36999:6817621] !-----3
[36999:6817621] !-----5
[36999:6817621] !-----2
[36999:6817621] !-----4
[36999:6817985] !-----6

也能夠?qū)崿F(xiàn)在兩個網(wǎng)絡(luò)回調(diào)結(jié)束之后箕母,再執(zhí)行self.homeAction。剛開始的信號量為0俱济,在創(chuàng)建的queue中嘶是,兩個請求都沒返回的情況下,會等在第一個dispatch_semaphore_wait蛛碌。當?shù)谝粋€請求結(jié)束后聂喇,發(fā)出dispatch_semaphore_signal,這時跳過第一個dispatch_semaphore_wait蔚携。第二個請求結(jié)束后希太,發(fā)出dispatch_semaphore_signal,跳過第二個dispatch_semaphore_wait酝蜒。這樣就實現(xiàn)了在兩個網(wǎng)絡(luò)回調(diào)結(jié)束之后誊辉,再執(zhí)行self.homeAction
不過需要注意的是亡脑,dispatch_semaphore_wait會使當前線程等待堕澄。就上述代碼而言,dispatch_semaphore_wait所在的線程是子線程霉咨,而網(wǎng)絡(luò)回調(diào)的線程是在主線程蛙紫,當調(diào)用到dispatch_semaphore_wait會使子線程發(fā)生等待,知道接收到主線程的兩個dispatch_semaphore_signal途戒,等待才會取消坑傅。如果把queue改成主線程,就會阻塞喷斋,因為主線程會一直等待唁毒,請求回調(diào)的block也是在主線程,永遠不會執(zhí)行星爪。

多個請求按順序同步執(zhí)行

使用dispatch_semaphore_t

    dispatch_semaphore_t semphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    dispatch_async(queue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[NetworkMgr sharedMgr] refreshServerAppConfigWithCompleteHandle:^{//main thread block
                NSLog(@"!-----1");
                dispatch_semaphore_signal(semphore);
            }];
        });
    });
    
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
        [[NetworkMgr sharedMgr] refreshBussinessRouterWithCompleteHandle:^{//main thread block
            NSLog(@"!-----2");
            dispatch_semaphore_signal(semphore);
        }];
    });
    
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
        NSLog(@"!-----3");
        if (self.homeAction) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.homeAction(0, nil);
            });
        }
    });

執(zhí)行順序

[37297:6848505] !-----1
[37297:6848505] !-----2
[37297:6848808] !-----3

打印結(jié)束顯示枉证,保證了第二個請求回調(diào)在第一個之后。剛開始創(chuàng)建的信號量為1移必,執(zhí)行第一個請求,回調(diào)結(jié)束后毡鉴,發(fā)出dispatch_semaphore_signal崔泵,才會執(zhí)行第二個請求,回調(diào)結(jié)束后才會執(zhí)行self.homeAction猪瞬。
這里也是要保證dispatch_semaphore_wait所在的線程必須和dispatch_semaphore_signal所在的線程不同憎瘸。

dispatch_semaphore_create

  dispatch_semaphore_t  dispatch_semaphore_create(long value);
  傳入的參數(shù)為long,輸出一個dispatch_semaphore_t類型且值為value的信號量陈瘦。
  值得注意的是幌甘,這里的傳入的參數(shù)value必須大于或等于0,否則dispatch_semaphore_create會返回NULL。

dispatch_semaphore_signal

  long dispatch_semaphore_signal(dispatch_semaphore_t dsema)
  這個函數(shù)會使傳入的信號量dsema的值加1锅风;
   dispatch_semaphore_signal的返回值為long類型酥诽,當返回值為0時表示當前并沒有線程等待其處理的信號量,其處理
  的信號量的值加1即可皱埠。當返回值不為0時肮帐,表示其當前有(一個或多個)線程等待其處理的信號量,并且該函數(shù)喚醒了一
  個等待的線程(當線程有優(yōu)先級時边器,喚醒優(yōu)先級最高的線程训枢;否則隨機喚醒)。
  dispatch_semaphore_wait的返回值也為long型忘巧。當其返回0時表示在timeout之前恒界,該函數(shù)所處的線程被成功喚醒。
  當其返回不為0時砚嘴,表示timeout發(fā)生十酣。

dispatch_semaphore_wait

  long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
  這個函數(shù)會使傳入的信號量dsema的值減1枣宫;
  這個函數(shù)的作用是這樣的婆誓,如果dsema信號量的值大于0,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語句也颤,并且將信號量的值減1洋幻;
  如果desema的值為0,那么這個函數(shù)就阻塞當前線程等待timeout(注意timeout的類型為dispatch_time_t翅娶,
  不能直接傳入整形或float型數(shù))文留,如果等待的期間desema的值被dispatch_semaphore_signal函數(shù)加1了,
  且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號量竭沫,那么就繼續(xù)向下執(zhí)行并將信號量減1燥翅。
  如果等待期間沒有獲取到信號量或者信號量的值一直為0,那么等到timeout時蜕提,其所處線程自動執(zhí)行其后語句森书。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谎势,隨后出現(xiàn)的幾起案子凛膏,更是在濱河造成了極大的恐慌,老刑警劉巖脏榆,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猖毫,死亡現(xiàn)場離奇詭異,居然都是意外死亡须喂,警方通過查閱死者的電腦和手機吁断,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門趁蕊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仔役,你說我怎么就攤上這事掷伙。” “怎么了骂因?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵炎咖,是天一觀的道長。 經(jīng)常有香客問我寒波,道長乘盼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任俄烁,我火速辦了婚禮绸栅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘页屠。我一直安慰自己粹胯,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布辰企。 她就那樣靜靜地躺著风纠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牢贸。 梳的紋絲不亂的頭發(fā)上竹观,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音潜索,去河邊找鬼臭增。 笑死,一個胖子當著我的面吹牛竹习,可吹牛的內(nèi)容都是我干的誊抛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼整陌,長吁一口氣:“原來是場噩夢啊……” “哼拗窃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起泌辫,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤随夸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后甥郑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡荤西,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年澜搅,在試婚紗的時候發(fā)現(xiàn)自己被綠了伍俘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡勉躺,死狀恐怖癌瘾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饵溅,我是刑警寧澤妨退,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站蜕企,受9級特大地震影響咬荷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轻掩,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一幸乒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唇牧,春花似錦罕扎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扮惦,卻和暖如春臀蛛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背径缅。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工掺栅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纳猪。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓氧卧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親氏堤。 傳聞我的和親對象是個殘疾皇子沙绝,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359