iOS 使用GCD控制網絡請求順序


 多個網絡請求同時執行,等所有網絡請求完成,再統一做其他操作,我們可能會想到dispatch_group_async、dispatch_group_notify結合使用。

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(@"任務一完成");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務二完成");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務三完成");
    });
    //在分組的所有任務完成后觸發
    dispatch_group_notify(group, queue, ^{
        NSLog(@"所有任務完成");
    });

 

或者使用柵欄

- (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(@"任務1-1完成");
    });
    dispatch_async(queue, ^{
        NSLog(@"任務1-2完成");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任務1-3完成");
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"以上任務都完成 dispatch_barrie完成");
    });
}

 

比如上述寫法,內部執行的是同步操作沒有問題,如果以上三個任務都是異步的,比如是網絡請求,那么就達不到我們想要的效果。因為異步,請求沒有回來,dispatch_group_notify或者dispatch_barrier_async已經執行了。

我們可以采用信號量或者dispatch_group_enter、dispatch_group_leave實現。

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

下述描述了常見場景下的代碼實現:包括順序執行和同時執行異步操作

順序執行 :

方式 : 信號量semaphore (必須放在子線程 dispatch_semaphore_wait會卡死主線程) (例:1執行完了執行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:^{
        }];
    });
}

 

執行到dispatch_semaphore_wait時,由於信號量為0,進行等待,請求1完成后調用dispatch_semaphore_signal ,信號量不再為0,接着執行請求2

方式: GCD dispatch_group_enter/leave (例: 1, 2 同時執行 執行完了再執行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同時執行
    
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);// 1 2 執行完 下面才會執行
    
    dispatch_group_enter(group);
    [self requestThreeWithBlock:^{
        dispatch_group_leave(group);
    }];
    
  // 1 2 3 都完成 才會執行
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"all request  done!");
    });
}

 

執行到dispatch_group_wait時,由於enter數不等於leave數,進行等待,請求1,2都完成后調用dispatch_group_leave ,enter數等於leave數,接着執行請求3。 請求1,2,3都執行后,dispatch_group_notify執行

方式三:回調中執行
- (void) serialByCallBack {
    [self requestOneWithSuccessBlock:^{
        [self requestTwoWithBlock:^{
        }];
    }];
}

 

low方法,請求一多,嵌套惡心


同時執行 :

方式:信號量
-(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  都完成 才會執行
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"all request  done!");
    });
}

 



擴充:循環請求情況 順序請求/同時請求


*模擬循環網絡請求 同時進行 統一回調 (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(@"任務%d完成",i);
                 dispatch_semaphore_signal(sema);
            });
             // 模擬請求 上
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

 

執行結果:

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

 




*模擬循環網絡請求 同時進行 統一回調 (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(@"任務%d完成",i);
            dispatch_group_leave(group);
        });
          // 模擬請求 ↑
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

 

執行結果:

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

 


*模擬循環網絡請求 順序進行 (GCD + 信號量方式)
- (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(@"任務%d完成",i);
                dispatch_semaphore_signal(sema);
            });
            // 模擬請求 上
           dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        }
        
       NSLog(@"全部搞完了");
    });
}

 

執行結果

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

 


*模擬循環網絡請求 順序進行 (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(@"任務%d完成",i);
            dispatch_group_leave(group);
        });
        // 模擬請求 ↑
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 順序執行與同步執行的不同點
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"全部搞完了");
    });
}

 

執行結果

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM