iOS 使用GCD控制網(wǎng)絡(luò)請求順序

多個網(wǎng)絡(luò)請求同時執(zhí)行凤巨,等所有網(wǎng)絡(luò)請求完成视乐,再統(tǒng)一做其他操作,我們可能會想到dispatch_group_async敢茁、dispatch_group_notify結(jié)合使用佑淀。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)一完成");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)二完成");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務(wù)三完成");
    });
    //在分組的所有任務(wù)完成后觸發(fā)
    dispatch_group_notify(group, queue, ^{
        NSLog(@"所有任務(wù)完成");
    });

或者使用柵欄

- (void)barrier {
//    dispatch_queue_t queue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1-1完成");
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1-2完成");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1-3完成");
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"以上任務(wù)都完成 dispatch_barrie完成");
    });
}

比如上述寫法,內(nèi)部執(zhí)行的是同步操作沒有問題彰檬,如果以上三個任務(wù)都是異步的伸刃,比如是網(wǎng)絡(luò)請求,那么就達不到我們想要的效果捧颅。因為異步景图,請求沒有回來,dispatch_group_notify或者dispatch_barrier_async已經(jīng)執(zhí)行了扣典。

我們可以采用信號量或者dispatch_group_enter妆毕、dispatch_group_leave實現(xiàn)。

核心思想:將異步變成同步

下述描述了常見場景下的代碼實現(xiàn):包括順序執(zhí)行和同時執(zhí)行異步操作

順序執(zhí)行 :

方式 : 信號量semaphore (必須放在子線程 dispatch_semaphore_wait會卡死主線程) (例:1執(zhí)行完了執(zhí)行2)
- (void)serialBySemaphore {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

        [self requestOneWithSuccessBlock:^{
            dispatch_semaphore_signal(semaphore);
        }];

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        [self requestTwoWithBlock:^{
        }];
    });
}

執(zhí)行到dispatch_semaphore_wait時贮尖,由于信號量為0笛粘,進行等待,請求1完成后調(diào)用dispatch_semaphore_signal 远舅,信號量不再為0闰蛔,接著執(zhí)行請求2

也可利用串行隊列異步執(zhí)行這樣寫:
    dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
    
    // 請求一
    dispatch_async(serialQueue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        // 模擬請求1 ↓
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(3);
            NSLog(@"任務(wù)1完成");
            dispatch_semaphore_signal(sema);
        });
        // 模擬請求 上
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
    
    // 請求二
    dispatch_async(serialQueue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        // 模擬請求2 ↓
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(3);
            NSLog(@"任務(wù)2完成");
            dispatch_semaphore_signal(sema);
        });
        // 模擬請求 上
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });

方式: GCD dispatch_group_enter/leave (例: 1, 2 同時執(zhí)行 執(zhí)行完了再執(zhí)行3)

-(void)serialByGroupWait {
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
    [self requestOneWithSuccessBlock:^{
        dispatch_group_leave(group);
    }];
    
    dispatch_group_enter(group);
    [self requestTwoWithBlock:^{
        dispatch_group_leave(group);
    }];
  // 1  2同時執(zhí)行
    
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);// 1 2 執(zhí)行完 下面才會執(zhí)行
    
    dispatch_group_enter(group);
    [self requestThreeWithBlock:^{
        dispatch_group_leave(group);
    }];
    
  // 1 2 3 都完成 才會執(zhí)行
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"all request  done!");
    });
}

執(zhí)行到dispatch_group_wait時图柏,由于enter數(shù)不等于leave數(shù)序六,進行等待,請求1蚤吹,2都完成后調(diào)用dispatch_group_leave 例诀,enter數(shù)等于leave數(shù),接著執(zhí)行請求3裁着。 請求1繁涂,2,3都執(zhí)行后二驰,dispatch_group_notify執(zhí)行

方式三:回調(diào)中執(zhí)行
- (void) serialByCallBack {
    [self requestOneWithSuccessBlock:^{
        [self requestTwoWithBlock:^{
        }];
    }];
}
low方法扔罪,請求一多,嵌套惡心


同時執(zhí)行 :

方式:信號量
-(void)concurrentBySemaphore {
 dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self requestOneWithSuccessBlock:^{
            dispatch_semaphore_signal(sema);
        }];
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self requestTwoWithSuccessBlock:^{
            dispatch_semaphore_signal(sema);
        }];
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}


方式:dispatch_group_enter
-(void)concurrentByGroup {
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
    [self requestOneWithSuccessBlock:^{
        dispatch_group_leave(group);
    }];
    
    dispatch_group_enter(group);
    [self requestTwoWithBlock:^{
        dispatch_group_leave(group);
    }];
    
  // 1 2  都完成 才會執(zhí)行
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"all request  done!");
    });
}


擴充:若干請求情況 順序請求/同時請求的寫法


*模擬若干網(wǎng)絡(luò)請求 同時進行 統(tǒng)一回調(diào) (GCD + 信號量方式)
- (void)concurrentTest1 {
    dispatch_group_t group = dispatch_group_create();
    for (int i = 0 ; i < 5; i++) {
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
             // 模擬請求 ↓
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(3);
                NSLog(@"任務(wù)%d完成",i);
                 dispatch_semaphore_signal(sema);
            });
             // 模擬請求 上
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

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

 00:21:38.413337+0800 mmmm[4595:182516] 任務(wù)1完成
 00:21:38.413337+0800 mmmm[4595:182518] 任務(wù)3完成
 00:21:38.413358+0800 mmmm[4595:182517] 任務(wù)2完成
 00:21:38.413358+0800 mmmm[4595:182515] 任務(wù)0完成
 00:21:38.413447+0800 mmmm[4595:182519] 任務(wù)4完成
 00:21:38.413843+0800 mmmm[4595:182428] 全部搞完了

*模擬若干網(wǎng)絡(luò)請求 同時進行 統(tǒng)一回調(diào) (GCD + group enter/leave 方式)
- (void)concurrentTest2 {
    dispatch_group_t group = dispatch_group_create();
    for (int i = 0 ; i < 5; i++) {
        dispatch_group_enter(group);
          // 模擬請求 ↓
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(3);
            NSLog(@"任務(wù)%d完成",i);
            dispatch_group_leave(group);
        });
          // 模擬請求 ↑
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

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

2019-04-12 00:26:38.607040+0800 mmmm[4641:184613] 任務(wù)0完成
2019-04-12 00:26:38.607043+0800 mmmm[4641:184612] 任務(wù)2完成
2019-04-12 00:26:38.607059+0800 mmmm[4641:184611] 任務(wù)3完成
2019-04-12 00:26:38.607067+0800 mmmm[4641:184610] 任務(wù)1完成
2019-04-12 00:26:38.607088+0800 mmmm[4641:184625] 任務(wù)4完成
2019-04-12 00:26:38.607353+0800 mmmm[4641:184559] 全部搞完了

*模擬若干網(wǎng)絡(luò)請求 順序進行 (GCD + 信號量方式)

demo1:利用一個信號的方式

- (void)serialTest1 {
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0 ; i < 5; i++) {
            NSLog(@"開始%d",i);
            // 模擬請求 ↓
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(3);
                NSLog(@"任務(wù)%d完成",i);
                dispatch_semaphore_signal(sema);
            });
            // 模擬請求 上
           dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        }
        
       NSLog(@"全部搞完了");
    });
}

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

2019-04-12 01:31:45.291818+0800 mmmm[5417:215007] 開始0
2019-04-12 01:31:48.297299+0800 mmmm[5417:215008] 任務(wù)0完成
2019-04-12 01:31:48.297746+0800 mmmm[5417:215007] 開始1
2019-04-12 01:31:51.298592+0800 mmmm[5417:215008] 任務(wù)1完成
2019-04-12 01:31:51.298841+0800 mmmm[5417:215007] 開始2
2019-04-12 01:31:54.300477+0800 mmmm[5417:215008] 任務(wù)2完成
2019-04-12 01:31:54.300908+0800 mmmm[5417:215007] 開始3
2019-04-12 01:31:57.305197+0800 mmmm[5417:215008] 任務(wù)3完成
2019-04-12 01:31:57.305623+0800 mmmm[5417:215007] 開始4
2019-04-12 01:32:00.311062+0800 mmmm[5417:215008] 任務(wù)4完成
2019-04-12 01:32:00.311407+0800 mmmm[5417:215007] 全部搞完了

demo2:利用串行隊列異步執(zhí)行(子線程執(zhí)行桶雀,保證信號不卡死主線程矿酵,因為串行隊列,依舊順序執(zhí)行)

- (void)serialTest3 {
    dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 5; i++) {
        // 請求一
        dispatch_async(serialQueue, ^{
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            // 模擬請求1 ↓
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(3);
                NSLog(@"任務(wù)%d完成",i);
                dispatch_semaphore_signal(sema);
            });
            // 模擬請求 上
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
    }

}


*模擬若干網(wǎng)絡(luò)請求 順序進行 (GCD + group enter/leave 方式)
- (void)serialTest2 {
    dispatch_group_t group = dispatch_group_create();
    for (int i = 0 ; i < 5; i++) {
        dispatch_group_enter(group);
        // 模擬請求 ↓
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(6 - i);
            NSLog(@"任務(wù)%d完成",i);
            dispatch_group_leave(group);
        });
        // 模擬請求 ↑
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 順序執(zhí)行與同步執(zhí)行的不同點
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

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

2019-04-12 00:33:46.020376+0800 mmmm[4748:188409] 任務(wù)0完成
2019-04-12 00:33:51.021098+0800 mmmm[4748:188409] 任務(wù)1完成
2019-04-12 00:33:55.022758+0800 mmmm[4748:188409] 任務(wù)2完成
2019-04-12 00:33:58.023783+0800 mmmm[4748:188409] 任務(wù)3完成
2019-04-12 00:34:00.027929+0800 mmmm[4748:188409] 任務(wù)4完成
2019-04-12 00:34:00.028444+0800 mmmm[4748:188374] 全部搞完了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矗积,一起剝皮案震驚了整個濱河市全肮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棘捣,老刑警劉巖辜腺,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡评疗,警方通過查閱死者的電腦和手機测砂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壤巷,“玉大人邑彪,你說我怎么就攤上這事‰驶” “怎么了寄症?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矩动。 經(jīng)常有香客問我有巧,道長,這世上最難降的妖魔是什么悲没? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任篮迎,我火速辦了婚禮,結(jié)果婚禮上示姿,老公的妹妹穿的比我還像新娘甜橱。我一直安慰自己,他們只是感情好栈戳,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布岂傲。 她就那樣靜靜地躺著,像睡著了一般子檀。 火紅的嫁衣襯著肌膚如雪镊掖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天褂痰,我揣著相機與錄音亩进,去河邊找鬼。 笑死缩歪,一個胖子當著我的面吹牛归薛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匪蝙,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼主籍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了骗污?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤沈条,失蹤者是張志新(化名)和其女友劉穎需忿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡屋厘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年涕烧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汗洒。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡议纯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溢谤,到底是詐尸還是另有隱情瞻凤,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布世杀,位于F島的核電站阀参,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瞻坝。R本人自食惡果不足惜蛛壳,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望所刀。 院中可真熱鬧衙荐,春花似錦、人聲如沸浮创。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒸矛。三九已至瀑罗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雏掠,已是汗流浹背斩祭。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乡话,地道東北人摧玫。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像绑青,于是被迫代替她去往敵國和親诬像。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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