iOS 使用dispatch_group實現(xiàn)分組并發(fā)網(wǎng)絡請求

鎮(zhèn)文圖.jpeg

實際開發(fā)中,網(wǎng)絡數(shù)據(jù)的并發(fā)請求是一個非常常見的需求,在一次需要使用多個網(wǎng)絡接口時,并發(fā)請求相對于串行請求有節(jié)省時間,速度快的優(yōu)勢。但有時我們也會有需要所有接口的數(shù)據(jù)全部獲取之后再進行下一步操作的需求,比如登錄流程中,多接口數(shù)據(jù)全部獲取完畢才顯示登錄成功,某一個復雜頁面,需要所有數(shù)據(jù)獲取完畢才進行視圖的繪制或刷新。今天本文就想用 dispatch_group來實現(xiàn)這個需求。

曾經(jīng)的落后方案

落后方案1 串行嵌套方案

串行嵌套方案應該屬于最常規(guī)的方案,將多個網(wǎng)絡接口嵌套請求,一個網(wǎng)絡請求數(shù)據(jù)獲取成功之后,在進行下一個網(wǎng)絡請求。

[網(wǎng)絡請求1:{
        成功或失敗:網(wǎng)絡請求2];

[網(wǎng)絡請求2:{
        成功或失敗:網(wǎng)絡請求3];

[網(wǎng)絡請求3:{
        成功或失敗:網(wǎng)絡請求4];

[網(wǎng)絡請求4:{
        成功或失敗:next step];

該方案的缺陷還比較明顯,請求數(shù)據(jù)的積累耗時非常嚴重,兩三個接口也許還好,如果一次需要獲取八九個接口數(shù)據(jù)之后,才進行下一步操作,那么也許需要等待數(shù)秒的時間,這樣的產(chǎn)品體驗是非常糟糕的。
從代碼層面說,嵌套的方式可讀性并不好,復雜不容易讀懂。
所以該方案確實很落后。。

落后方案2 BOOL值監(jiān)控法

該方案是本人接觸dispatch_group前,自創(chuàng)的并發(fā)請求數(shù)據(jù)獲取監(jiān)控方式,如有雷同,全屬巧合。
針對每一個請求設置一個對應的BOOL值,待每一個BOOL值都為YES時,執(zhí)行下一步操作。

BOOL reqOneCompletion;
BOOL reqTwoCompletion;
BOOL reqThreeCompletion;

-  (void)network {
    [網(wǎng)絡請求1:{
        成功或失敗:reqOneCompletion = YES
        [self nextStep]];

    [網(wǎng)絡請求2:{
        成功或失敗:reqTwoCompletion = YES
        [self nextStep]];

    [網(wǎng)絡請求3:{
        成功或失敗:reqThreeCompletion = YES
        [self nextStep]];
}


-  (void)nextStep {
    if (reqOneCompletion && reqTwoCompletion && reqThreeCompletion) {
        // 執(zhí)行一下步操作
    }
}

在該方案中,本人通過設置BOOL值和網(wǎng)絡請求任務之間的映射關系,監(jiān)控網(wǎng)絡請求的數(shù)據(jù)是否返回完畢,最后再判斷是否可以執(zhí)行下一步操作。該方案雖然具有可行性,但代碼的可讀性上依舊比較糟糕,網(wǎng)絡請求任務和BOOL之間的映射關系存在出錯的可能性,雖然邏輯上和后文講解dispatch_group一致,但比較土味,我們還是需要更潮一些的方法。

使用dispatch_group方案

dispatch_group是GCD(Grand Central Dispatch)中的一組方法,他有一個組的概念,可以把相關的任務歸并到一個組內(nèi)來執(zhí)行,通過監(jiān)聽組內(nèi)所有任務的執(zhí)行情況來做相應處理。
dispatch_group的使用主要是4個方法

  • dispatch_group_create
  • dispatch_group_async
  • dispatch_group_enter
  • dispatch_group_leave
  • dispatch_group_notify
dispatch_group_create

創(chuàng)建任務組,創(chuàng)建任務組后才能把任務加入進組內(nèi)。

dispatch_group_t dispatch_group_create(void);
dispatch_group_async

通過異步執(zhí)行任務。

void dispatch_group_async(dispatch_group_t group,
                          dispatch_queue_t queue,
                          dispatch_block_t block);
  • group :對應的任務組,之后可以通過dispatch_group_wait或者dispatch_group_notify監(jiān)聽任務組內(nèi)任務的執(zhí)行情況
  • queue :block任務執(zhí)行的線程隊列,任務組內(nèi)不同任務的隊列可以不同
  • block : 執(zhí)行任務的block
dispatch_group_enter

用于添加對應任務組中的未執(zhí)行完畢的任務數(shù),執(zhí)行一次,未執(zhí)行完畢的任務數(shù)加1,當未執(zhí)行完畢任務數(shù)為0的時候,才會使dispatch_group_wait解除阻塞和dispatch_group_notify的block執(zhí)行。

void dispatch_group_enter(dispatch_group_t group);
dispatch_group_leave

用于減少任務組中的未執(zhí)行完畢的任務數(shù),執(zhí)行一次,未執(zhí)行完畢的任務數(shù)減1,dispatch_group_enter和dispatch_group_leave要匹配,不然系統(tǒng)會認為group任務沒有執(zhí)行完畢。

void dispatch_group_leave(dispatch_group_t group);
dispatch_group_notify

用于監(jiān)控group中的任務數(shù),任務數(shù)歸0時,方法執(zhí)行。這個也是并發(fā)請求關鍵一步,當他執(zhí)行時代表并發(fā)請求數(shù)據(jù)獲取完畢。

void dispatch_group_notify(dispatch_group_t group,
                           dispatch_queue_t queue, 
                           dispatch_block_t block);
  • group :需要監(jiān)聽的任務組
  • queue :block任務執(zhí)行的線程隊列,和之前group執(zhí)行的線程隊列無關
  • block :任務組執(zhí)行完畢時需要執(zhí)行的任務block
dispatch_group_wait

等待組任務完成,會阻塞當前線程,當任務組執(zhí)行完畢時,才會解除阻塞當前線程。

long dispatch_group_wait(dispatch_group_t group, 
                         dispatch_time_t timeout);
  • group :需要等待的任務組
  • timeout :等待的超時時間(即等多久),單位為dispatch_time_t。如果設置為DISPATCH_TIME_FOREVER,則會一直等待(阻塞當前線程),直到任務組執(zhí)行完畢

以上dispatch_group的方法介紹完畢,我們來看看具體使用的方式。

實際使用:

dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //請求1
        [網(wǎng)絡請求1:{
        成功或失?。篸ispatch_group_leave(group);
        }];
    });

    dispatch_group_enter(group);
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //請求2
        [網(wǎng)絡請求2:{
        成功或失?。篸ispatch_group_leave(group);
        }];
    });

    dispatch_group_enter(group);
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //請求3
        [網(wǎng)絡請求3:{
        成功或失?。篸ispatch_group_leave(group);
        }];
    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        //界面刷新
        next step
    });

該并發(fā)網(wǎng)絡請求方案的優(yōu)勢相對于上文介紹的兩種落后的方式來說就很明顯了。異步請求,更加的節(jié)省網(wǎng)絡請求等待的時間,流暢度和體驗上更加好。可讀性方面,不用開發(fā)者自己去寫一些映射關系作為監(jiān)控,使用GCD自帶的組內(nèi)任務計數(shù),更加的準確,方便,代碼讀起來也更加的直觀。??????

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

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

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