iOS面試-使用GCD處理幾個(gè)線程之間的依賴關(guān)系。

有時(shí)候我們在開發(fā)過程中,會有這樣的需求蓖租,a任務(wù)開始執(zhí)行的前提是b任務(wù)執(zhí)行完成,c任務(wù)開始執(zhí)行需要等a稻艰、b兩個(gè)異步任務(wù)完成涯鲁,即a依賴于b同木,c又依賴a,這種需求我們可以使用的GCD來處理黍氮。

    //創(chuàng)建分組

    dispatch_group_t group =dispatch_group_create();

    //創(chuàng)建隊(duì)列

    dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

    //往分組中添加任務(wù)

    dispatch_group_async(group, queue, ^{

        [NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作

        NSLog(@"11111 %@", [NSThreadcurrentThread]);

    });

    //往分組中添加任務(wù)

    dispatch_group_async(group, queue, ^{

        [NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作

        NSLog(@"2222 %@", [NSThreadcurrentThread]);

    });

    //分組中任務(wù)完成以后通知該block執(zhí)行

    dispatch_group_notify(group, queue, ^{

        NSLog(@"完成 %@", [NSThreadcurrentThread]);

        dispatch_async(dispatch_get_main_queue(), ^{

            NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);

        });

    });

執(zhí)行結(jié)果:

2017-10-24 11:33:40.426 iOSTest[34497:828682] 2222 0x600000260080>{number = 3, name = (null)} 
2017-10-24 11:33:41.426 iOSTest[34497:828660] 11111 0x608000261d80>{number = 4, name = (null)} 
2017-10-2411:33:41.427 iOSTest[34497:828660] 完成 0x608000261d80>{number = 4, name = (null)} 
2017-10-2411:33:41.427 iOSTest[34497:828365] 通知主線程刷新UI 0x60800007b980>{number = 1, name = main}
這樣我們使用group可以實(shí)現(xiàn)幾個(gè)任務(wù)之間的依賴關(guān)系唐含。

然而有時(shí)我們的任務(wù)一層一層的嵌套了多個(gè)Block浅浮,這個(gè)時(shí)候,就應(yīng)該使用如下代碼方式:

//創(chuàng)建分組

    dispatch_group_t group =dispatch_group_create();

    //創(chuàng)建隊(duì)列

    dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

    //往分組中添加任務(wù)

    dispatch_group_async(group, queue, ^{

        void (^task)(void) = ^{

            [NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作

            NSLog(@"11111 %@", [NSThreadcurrentThread]);

        };

        dispatch_async(dispatch_get_global_queue(0,0), task);

        NSLog(@"11111---- %@", [NSThreadcurrentThread]);

    });

    //往分組中添加任務(wù)

    dispatch_group_async(group, queue, ^{

        void (^task)(void) = ^ {

            [NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作

            NSLog(@"2222 %@", [NSThreadcurrentThread]);

        };

        dispatch_async(dispatch_get_global_queue(0,0), task);

        NSLog(@"2222------- %@", [NSThreadcurrentThread]);

    });

    //分組中任務(wù)完成以后通知該block執(zhí)行

    dispatch_group_notify(group, queue, ^{

        NSLog(@"完成 %@", [NSThreadcurrentThread]);

        dispatch_async(dispatch_get_main_queue(), ^{

            NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);

        });

    });

執(zhí)行結(jié)果:

2017-10-24 11:44:06.447 iOSTest[34981:881063] 2222------- {number = 4, name = (null)}
2017-10-2411:44:06.447 iOSTest[34981:881046] 11111---- {number = 3, name = (null)}
2017-10-24 11:44:06.448iOSTest[34981:881046] 完成 0x600000071f40>{number = 3, name = (null)} 
2017-10-24 11:44:06.450iOSTest[34981:880987] 通知主線程刷新UI 0x60000006c340>{number = 1, name = main}
 2017-10-2411:44:07.450 iOSTest[34981:881064] 2222 0x6000000708c0>{number = 5, name = (null)} 
2017-10-2411:44:08.452 iOSTest[34981:881049] 11111 0x61000006d5c0>{number = 6, name = (null)}

根據(jù)執(zhí)行結(jié)果可以看出捷枯,當(dāng)主線程執(zhí)行的時(shí)候滚秩,然而其他兩個(gè)任務(wù)中并沒有真正的完成,因?yàn)榱硗鈨蓚€(gè)任務(wù)中嵌套了子任務(wù)淮捆,那問題來了郁油,其他兩個(gè)任務(wù)還沒有完成就執(zhí)行主線程,但是我們需要的是其他兩個(gè)任務(wù)完成才需要執(zhí)行主線程攀痊,別急桐腌,group給我們提供了dispatch_group_enter()與dispatch_group_leave()方法來組合運(yùn)用,值得注意的是苟径,這兩個(gè)方法一定需要成對使用案站,要不然有時(shí)間又出現(xiàn)一些莫名其妙的bug問題。
代碼如下:

//創(chuàng)建分組

    dispatch_group_t group =dispatch_group_create();

    //創(chuàng)建隊(duì)列

    dispatch_queue_t queue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

    //往分組中添加任務(wù)

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        void (^task)(void) = ^{

            [NSThreadsleepForTimeInterval:2];//模擬耗時(shí)操作

            NSLog(@"11111 %@", [NSThreadcurrentThread]);

            dispatch_group_leave(group);

        };

        dispatch_async(dispatch_get_global_queue(0,0), task);

        NSLog(@"11111---- %@", [NSThreadcurrentThread]);

    });

    //往分組中添加任務(wù)

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        void (^task)(void) = ^ {

            [NSThreadsleepForTimeInterval:1];//模擬耗時(shí)操作

            NSLog(@"2222 %@", [NSThreadcurrentThread]);

            dispatch_group_leave(group);

        };

        dispatch_async(dispatch_get_global_queue(0,0), task);

        NSLog(@"2222------- %@", [NSThreadcurrentThread]);

    });

    

    //分組中任務(wù)完成以后通知該block執(zhí)行

    dispatch_group_notify(group, queue, ^{

        NSLog(@"完成 %@", [NSThreadcurrentThread]);

        dispatch_async(dispatch_get_main_queue(), ^{

            NSLog(@"通知主線程刷新UI %@", [NSThreadcurrentThread]);

        });

    });

執(zhí)行結(jié)果如下:

2017-10-24 11:48:05.641 iOSTest[35128:902591] 11111---- {number = 3, name = (null)}
2017-10-2411:48:05.641 iOSTest[35128:902608] 2222------- {number = 4, name = (null)}
2017-10-24 11:48:06.644iOSTest[35128:902609] 2222 0x60000006cb00>{number = 5, name = (null)} 
2017-10-24 11:48:07.644iOSTest[35128:902593] 11111 0x6080000721c0>{number = 6, name = (null)} 
2017-10-24 11:48:07.644iOSTest[35128:902593] 完成 0x6080000721c0>{number = 6, name = (null)} 
2017-10-24 11:48:07.645iOSTest[35128:902524] 通知主線程刷新UI 0x61000006e280>{number = 1, name = main}

這樣我們想要的得到的結(jié)果就實(shí)現(xiàn)了棘街。

A蟆盐,B,C三個(gè)任務(wù)并發(fā)執(zhí)行,但是C要等A遭殉,B執(zhí)行完成之后再執(zhí)行石挂。

信號量:
// 創(chuàng)建一個(gè)信號,value:信號量
dispatch_semaphore_create(<#long value#>)
// 使某個(gè)信號的信號量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)
// 某個(gè)信號進(jìn)行等待或等待降低信號量 timeout:等待時(shí)間险污,永遠(yuǎn)等待為 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
正常的使用順序是先降低然后再提高痹愚,這兩個(gè)函數(shù)通常成對使用。

兩種方法

-(void)dispatch_group_function1
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
        NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            // 請求完成罗心,可以通知界面刷新界面等操作
            NSLog(@"第一步網(wǎng)絡(luò)請求完成");
            // 使信號的信號量+1里伯,這里的信號量本來為0,+1信號量為1(綠燈)
            dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        // 以下還要進(jìn)行一些其他的耗時(shí)操作
        NSLog(@"耗時(shí)操作繼續(xù)進(jìn)行");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
        NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            // 請求完成渤闷,可以通知界面刷新界面等操作
            NSLog(@"第二步網(wǎng)絡(luò)請求完成");
            // 使信號的信號量+1,這里的信號量本來為0脖镀,+1信號量為1(綠燈)
            dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        // 以下還要進(jìn)行一些其他的耗時(shí)操作
        NSLog(@"耗時(shí)操作繼續(xù)進(jìn)行");
        dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"刷新界面等在主線程的操作");
    });
}

2019-02-24 18:19:16.251067+0800 Semaphore[33094:12267734] 耗時(shí)操作繼續(xù)進(jìn)行
2019-02-24 18:19:16.251071+0800 Semaphore[33094:12267735] 耗時(shí)操作繼續(xù)進(jìn)行
2019-02-24 18:19:16.549563+0800 Semaphore[33094:12267748] 第一步網(wǎng)絡(luò)請求完成
2019-02-24 18:19:18.091922+0800 Semaphore[33094:12267737] 第二步網(wǎng)絡(luò)請求完成
2019-02-24 18:19:18.092222+0800 Semaphore[33094:12267662] 刷新界面等在主線程的操作

設(shè)定的信號值為2飒箭,先執(zhí)行兩個(gè)線程,等執(zhí)行完一個(gè)蜒灰,才會繼續(xù)執(zhí)行下一個(gè)弦蹂,保證同一時(shí)間執(zhí)行的線程數(shù)不超過2。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //任務(wù)1
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 1");
        sleep(1);
        NSLog(@"complete task 1");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)2
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 2");
        sleep(1);
        NSLog(@"complete task 2");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)3
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 3");
        sleep(1);
        NSLog(@"complete task 3");
        dispatch_semaphore_signal(semaphore);
    });
2019-02-24 18:31:02.447769+0800 Semaphore[33286:12284312] run task 1
2019-02-24 18:31:02.447767+0800 Semaphore[33286:12284310] run task 2
2019-02-24 18:31:03.450756+0800 Semaphore[33286:12284312] complete task 1
2019-02-24 18:31:03.450756+0800 Semaphore[33286:12284310] complete task 2
2019-02-24 18:31:03.450997+0800 Semaphore[33286:12284311] run task 3
2019-02-24 18:31:04.454259+0800 Semaphore[33286:12284311] complete task 3
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末强窖,一起剝皮案震驚了整個(gè)濱河市凸椿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翅溺,老刑警劉巖脑漫,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件髓抑,死亡現(xiàn)場離奇詭異,居然都是意外死亡优幸,警方通過查閱死者的電腦和手機(jī)吨拍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來网杆,“玉大人羹饰,你說我怎么就攤上這事√既矗” “怎么了队秩?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昼浦。 經(jīng)常有香客問我馍资,道長,這世上最難降的妖魔是什么座柱? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任迷帜,我火速辦了婚禮,結(jié)果婚禮上色洞,老公的妹妹穿的比我還像新娘戏锹。我一直安慰自己,他們只是感情好火诸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布锦针。 她就那樣靜靜地躺著,像睡著了一般置蜀。 火紅的嫁衣襯著肌膚如雪奈搜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天盯荤,我揣著相機(jī)與錄音馋吗,去河邊找鬼。 笑死秋秤,一個(gè)胖子當(dāng)著我的面吹牛宏粤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灼卢,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绍哎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鞋真?” 一聲冷哼從身側(cè)響起崇堰,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后海诲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體繁莹,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年饿肺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒋困。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敬辣,死狀恐怖雪标,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溉跃,我是刑警寧澤村刨,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站撰茎,受9級特大地震影響嵌牺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜龄糊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一逆粹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炫惩,春花似錦僻弹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筋蓖,卻和暖如春卸耘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粘咖。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工蚣抗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瓮下。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓忠聚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唱捣。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355