在做項目的時候往往會出現(xiàn)多圖上傳的功能,而恰巧服務器可能只支持單張上傳痪署,所以你要遍歷請求尸红,而全部上傳完成后可能還要刷新列表啊或者給個提示框啊等需求。
有些人可能會一個網(wǎng)絡請求成功回調(diào)里面再嵌套一個,類推逛薇,如果上傳9張圖就要嵌套9次捺疼,很顯然這樣的代碼看上去有點low而且非并發(fā)耗時比較慢,推薦使用gcd group 組永罚。話不多說上代碼:
//創(chuàng)建一個組
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多個網(wǎng)絡請求
dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
//異步網(wǎng)絡請求
int x = arc4random() % 5;
//模擬網(wǎng)絡請求快慢不確定的情況
sleep(x);
NSLog(@"group 請求成功OR請求失敗 %d!",i);
});
}
NSLog(@"group開始 網(wǎng)絡請求!");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//網(wǎng)絡請求完畢 回到主線程更新UI 或者做些其它的操作
NSLog(@"group所有請求完畢!!!");
});
使用dispatch_group_async函數(shù)將多個任務關聯(lián)到一個Dispatch Group和相應的queue中啤呼,group會并發(fā)地同時執(zhí)行這些任務。而且Dispatch Group可以用來阻塞一個線程, 直到group關聯(lián)的所有的任務完成執(zhí)行調(diào)用dispatch_group_notify方法,這樣就達到了想要的效果。
當然你也可以不使用dispatch_group_async函數(shù),轉(zhuǎn)而使用dispatch_group_enter和dispatch_group_leave,注意這里要配套使用哦延塑。
dispatch_group_enter:通知group,下面的任務馬上要放到group中執(zhí)行了醇锚。
dispatch_group_leave:通知group,任務完成了坯临,該任務要從group中移除了。
//創(chuàng)建一個組
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多個網(wǎng)絡請求
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//異步網(wǎng)絡請求
int x = arc4random() % 5;
//模擬網(wǎng)絡請求快慢不確定的情況
sleep(x);
NSLog(@"group 請求成功OR請求失敗 %d!",i);
dispatch_group_leave(group);
});
}
NSLog(@"group開始 網(wǎng)絡請求!");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//網(wǎng)絡請求完畢 回到主線程更新UI 或者做些其它的操作
NSLog(@"group所有請求完畢!!!");
});
還有一種情況恋昼,比如要做一個相冊功能看靠,也是多圖上傳,但是要有規(guī)律按順序上傳液肌。這里就推薦使用dispatch_semaphore_t 信號量,也是利用線程阻塞來實現(xiàn)挟炬。直接上代碼:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
/// 創(chuàng)建一個線程"001" 確保之后不要阻塞主線程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
/// 創(chuàng)建一個信號量 數(shù)值為1 信號量可以讓線程阻塞等待
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (int i = 0; i<9; i++) {
/// 模仿9個請求任務
/// 執(zhí)行dispatch_semaphore_wait 信號量數(shù)值 -1.
/// 當i為0此時的信號量數(shù)值為0, 當此時的信號量大于等于0繼續(xù)執(zhí)行wait函數(shù)下面的語句.
/// 當i為1此時的信號量數(shù)值為-1, 阻塞當前線程 阻塞時長為DISPATCH_TIME_FOREVER, 不執(zhí)行wait函數(shù)下面的語句.
/// 只有等到執(zhí)行i為0 的 dispatch_semaphore_signal 方法執(zhí)行, 信號量數(shù)值+1 為0, 喚醒 繼續(xù)執(zhí)行wait函數(shù)下面的語句.
/// 以此類推循環(huán).
NSLog(@"當前線程:%@",[NSThread currentThread]);
/// ******這是一個網(wǎng)絡請求開始******
dispatch_async(dispatch_get_global_queue(0, 0), ^{
/// 模擬異步網(wǎng)絡請求
int x = arc4random() % 2;
/// 模擬網(wǎng)絡請求快慢
sleep(x);
NSLog(@"執(zhí)行任務代號:%d",i);
/// 任務結(jié)束 信號量數(shù)值+1 解放線程"001" 阻塞
dispatch_semaphore_signal(semaphore);
});
/// ******這是一個網(wǎng)絡請求結(jié)束******
/// 信號量減1 變?yōu)樨摂?shù) 當前線程"001" 阻塞
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
});
}
如果需要兩者結(jié)合使用呢也是可以的,這樣即能按順序上傳嗦哆,又能在上傳后收到通知做一些提示或者其它操作谤祖,請看代碼:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
/// 創(chuàng)建一個線程"001" 確保之后不要阻塞主線程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_group_t group = dispatch_group_create();
/// 創(chuàng)建一個信號量 數(shù)值為0
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (int i = 0; i<9; i++)
{
/// 模仿9個請求任務
dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
// /// 異步網(wǎng)絡請求
// int x = arc4random() % 2;
// /// 模擬網(wǎng)絡請求快慢不確定的情況
// sleep(x);
NSLog(@"執(zhí)行任務:%d 線程:%@",i,[NSThread currentThread]);
/// 任務結(jié)束 信號量數(shù)值+1 解放線程"001" 阻塞
dispatch_semaphore_signal(semaphore);
});
/// 信號量減1 變?yōu)樨摂?shù) 當前線程"001" 阻塞
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//NSLog(@"阻塞線程:%@",[NSThread currentThread]);
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
/// 網(wǎng)絡請求完畢 回到主線程更新UI 或者做些其它的操作
NSLog(@"所有任務執(zhí)行完畢!!!");
});
});
}
想要順序(同步)執(zhí)行異步任務的話,可以把一個個異步任務放在串行隊列里面去執(zhí)行老速,代碼如下:
dispatch_queue_t queue = dispatch_queue_create("serial",DISPATCH_QUEUE_SERIAL);
///在串行隊列中 執(zhí)行第一個異步任務
dispatch_async(queue, ^{
NSLog(@"1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:5];
NSLog(@"xxxxxxxxxxxxxx");
});
///在串行隊列中 執(zhí)行第二個異步任務
dispatch_async(queue, ^{
NSLog(@"2---%@", [NSThread currentThread]);
});
///在串行隊列中 執(zhí)行第三個異步任務
dispatch_async(queue, ^{
NSLog(@"3---%@", [NSThread currentThread]);
});
如果有不同見解歡迎討論粥喜,有錯誤還請指出,博主加以改正橘券,謝謝!
轉(zhuǎn)載請說明出處额湘,代碼在這里。請不要吝嗇您的star