在開發(fā)中我們常常會遇到在一個界面中需要異步請求多個接口苛蒲,通過不同接口的返回數(shù)據(jù)刷新界面不同控件的需求。這種情況下有兩種選擇绿满,一種是 依次請求多個接口臂外,分別拿到數(shù)據(jù) 這種方式有兩種方法實現(xiàn):1: 接口回調(diào)嵌套(容易造成代碼金字塔,寫法low)2:管理多線程 使異步的請求操作變成依次執(zhí)行喇颁。 依次請求接口的方式很容易造成用戶在當前界面請求時間過長而影響體驗漏健,這就需要我們 并發(fā)的發(fā)起多個異步請求了,但有時候我們界面刷新時 不同界面間的數(shù)據(jù)存在 關聯(lián)橘霎,我們得在所有請求完成后才能 統(tǒng)一 對界面刷新或者其它操作蔫浆, 下面我簡單介紹使用GCD 使 監(jiān)聽異步請求全部完成 和 異步請求依次進行 的方式。
1. 監(jiān)聽異步請求全部完成 再完成刷新界面等操作
先上代碼:
dispatch_group_t group = dispatch_group_create();//創(chuàng)建隊列組
dispatch_group_enter(group); //隊列組中加入一個異步操作
//網(wǎng)絡請求
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第一個完成");
//隊列組中移除一個異步操作
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第二個完成");
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第三個完成");
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"請求全部完成 w回到主線程了");
});
使用了CGD 中隊列組方式茎毁,通過發(fā)起請求時 加入一個異步事件到隊列組克懊,請求完成后 將其移除, 最終監(jiān)聽隊列組中無操作時 即為所有請求事件已完成七蜘。 要注意的一點是 網(wǎng)絡請求本身就是異步的操作, 所以不能寫成:
dispatch_async(queue, ^{
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第一個完成");
dispatch_semaphore_signal(semaphore); //信號量 +1
}];
}
2. 使異步的網(wǎng)絡請求依次進行
//新建一個串行(并行 都可以)隊列墙懂, 在該 隊列中對 所有 的網(wǎng)絡請求做操作
dispatch_queue_t queue = dispatch_queue_create("sdsdsdsd", DISPATCH_QUEUE_SERIAL);
//創(chuàng)建信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); //初始為 0
NSLog(@"開始執(zhí)行3");
dispatch_async(queue, ^{
NSLog(@"開始執(zhí)行1");
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第一個完成");
dispatch_semaphore_signal(semaphore); //信號量 +1
}];
//信號量為0 時不 執(zhí)行 (如果信號量 不為 0 時才往下執(zhí)行并且 信號量 -1)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"開始執(zhí)行2");
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第二個完成");
dispatch_semaphore_signal(semaphore); //信號量 +1
}];
//信號量為0 時不 執(zhí)行 (如果信號量 不為 0 時才往下執(zhí)行并且 信號量 -1)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"開始執(zhí)行3");
[[HttpTool sharedJsonClient] requestJsonDataWithPath:newUrlString andBlock:^(id _Nonnull data, NSError * _Nonnull error) {
NSLog(@"請求第三個完成");
dispatch_async(queue, ^{
dispatch_semaphore_signal(semaphore); //信號量 +1
});
}];
//信號量為0 時不 執(zhí)行 (如果信號量 不為 0 時才往下執(zhí)行并且 信號量 -1)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"在當前線程中繼續(xù)執(zhí)行");
});
需要注意的事項是:
- 如果在 主隊列中 做 信號量的加減和wait等操作 橡卤,dispatch_semaphore_wait 方式會阻塞當前線程(主線程),而網(wǎng)絡請求的回調(diào)默認是回到主線程中 處理事件的损搬, 由此會導致 主線程中 dispatch_semaphore_signal(semaphore); 方法不會執(zhí)行碧库,造成主線程死鎖。 所以巧勤,只能新建一個 串行或者 并行 隊列(新建隊列的時候會開一條線程管理事件) 對 網(wǎng)絡請求操作 做管理 (不能在主隊列)
- 使用AFN網(wǎng)絡請求操作會自動開啟子線程執(zhí)行嵌灰,而請求完成后的操作會自動回到主線程。