去面試的時(shí)候,遇到面試官問這個(gè)問題。
多個(gè)請求返回成功后再執(zhí)行相關(guān)操作的方式有三種:
第一種:計(jì)數(shù)器變量
每個(gè)頁面需要發(fā)送請求的數(shù)量一般是確定的。那么就聲明一個(gè)Int型的變量來存儲(chǔ)總的請求數(shù),再聲明另一個(gè)變量來存儲(chǔ)當(dāng)前請求成功并返回的所有請求數(shù)。
代碼如下:
//多請求成功后執(zhí)行方式一
-(void)requestsTest1{
int allrequestNum = 3; //請求總數(shù)
__block int presentNum = 0; //當(dāng)前成功請求數(shù)
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(quene, ^{
NSLog(@"任務(wù)1開始執(zhí)行");
sleep(2);
NSLog(@"任務(wù)1執(zhí)行完畢");
if (++presentNum == allrequestNum) {
[self allCompelete];
}
});
dispatch_async(quene, ^{
NSLog(@"任務(wù)2開始執(zhí)行");
sleep(4);
NSLog(@"任務(wù)2執(zhí)行完畢");
if (++presentNum == allrequestNum) {
[self allCompelete];
}
});
dispatch_async(quene, ^{
NSLog(@"任務(wù)3開始執(zhí)行");
sleep(6);
NSLog(@"任務(wù)3執(zhí)行完畢");
if (++presentNum == allrequestNum) {
[self allCompelete];
}
});
}
-(void)allCompelete{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"所有任務(wù)執(zhí)行完畢");
});
}
輸出如下:

使用計(jì)算器變量
第二種:GCD的group方式
主要使用group的兩個(gè)方法:
dispatch_group_enter:通知group,下面的任務(wù)將要要放到group中執(zhí)行。
dispatch_group_leave:通知group,任務(wù)已完成,該任務(wù)要從group中移除。
這兩種通知可以在多線程間自由穿梭使用的
這兩個(gè)方法必須成對出現(xiàn),少了誰都要蹦。
代碼如下:
//多請求成功后執(zhí)行方式二
-(void)requestsTest2{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(group);
dispatch_group_enter(group);
dispatch_group_enter(group);
dispatch_group_async(group, quene, ^{
NSLog(@"任務(wù)1開始執(zhí)行");
sleep(2);
dispatch_group_leave(group);
NSLog(@"任務(wù)1執(zhí)行完畢");
});
dispatch_group_async(group, quene, ^{
NSLog(@"任務(wù)2開始執(zhí)行");
sleep(4);
dispatch_group_leave(group);
NSLog(@"任務(wù)2執(zhí)行完畢");
});
dispatch_group_async(group, quene, ^{
NSLog(@"任務(wù)3開始執(zhí)行");
sleep(6);
dispatch_group_leave(group);
NSLog(@"任務(wù)3執(zhí)行完畢");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任務(wù)執(zhí)行完畢");
});
}
輸出如下:

GCD的group方式
第三種:信號(hào)量
主要利用信號(hào)量值為0時(shí)會(huì)阻塞線程執(zhí)行后面的代碼。
這里也主要使用信號(hào)量的三個(gè)方法:
dispatch_semaphore_create 創(chuàng)建一個(gè)semaphore
dispatch_semaphore_signal 發(fā)送一個(gè)信號(hào),信號(hào)量值+1
dispatch_semaphore_wait 等待信號(hào),信號(hào)量值-1
dispatch_semaphore_signal 和 dispatch_semaphore_wait基本都是成對的出現(xiàn),而且要注意信號(hào)量值為0時(shí)會(huì)阻塞線程的情況。一般是先使用dispatch_semaphore_signal 再使用dispatch_semaphore_wait。
代碼如下:
//多請求成功后執(zhí)行方式三:信號(hào)量
-(void)requestsTest3{
int allrequestNum = 3; //請求總數(shù)
__block int presentNum = 0; //當(dāng)前成功請求數(shù)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(quene, ^{ //這里用一個(gè)異步并發(fā)是因?yàn)楸苊鈊ispatch_semaphore_wait阻塞主線程
dispatch_async(quene, ^{
NSLog(@"任務(wù)1開始執(zhí)行");
sleep(2);
NSLog(@"任務(wù)1執(zhí)行完畢");
if (++presentNum == allrequestNum) {//當(dāng)返回?cái)?shù)等于總請求數(shù)
dispatch_semaphore_signal(semaphore);
}
});
dispatch_async(quene, ^{
NSLog(@"任務(wù)2開始執(zhí)行");
sleep(4);
NSLog(@"任務(wù)2執(zhí)行完畢");
if (++presentNum == allrequestNum) {
dispatch_semaphore_signal(semaphore);
}
});
dispatch_async(quene, ^{
NSLog(@"任務(wù)3開始執(zhí)行");
sleep(6);
NSLog(@"任務(wù)3執(zhí)行完畢");
if (++presentNum == allrequestNum) {
dispatch_semaphore_signal(semaphore);
}
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"所有任務(wù)執(zhí)行完畢");
});
});
}
輸出如下:

信號(hào)量
其實(shí)第一種和第三種差不多,都需要使用一個(gè)變量來存儲(chǔ)總請求數(shù)和當(dāng)前成功返回?cái)?shù)。