原文:Using Dispatch Groups to Wait for Multiple Web Services
假設(shè)你的應(yīng)用在啟動(dòng)時(shí)必須向服務(wù)端進(jìn)行一連串的請(qǐng)求.這些請(qǐng)求可能是獲取配置信息.舉個(gè)例子,當(dāng)你的應(yīng)用啟動(dòng)時(shí)可能會(huì)向服務(wù)端請(qǐng)求一些配置信息.這個(gè)配置信息可能需要多個(gè)請(qǐng)求組合而成.
你想通過(guò)調(diào)用一個(gè)方法去啟動(dòng)這些請(qǐng)求,然后全部請(qǐng)求完成后,在一個(gè)completion block
里面完成你的業(yè)務(wù)邏輯.但是這些請(qǐng)求相互間沒有什么聯(lián)系,我們應(yīng)該如何做呢?
在你看到你的代碼像下面的這個(gè)樣子時(shí),可能你需要重構(gòu)你的代碼.
}];
}];
}];
}];
}];
初始化一個(gè)dispatch group
很簡(jiǎn)單:
dispatch_group_t serviceGroup = dispatch_group_create();
向dispatch group中添加任務(wù)
有兩種方法,第一種是在這個(gè)dispatch group中添加你的代碼塊,然后這些代碼塊會(huì)運(yùn)行在你指定的queue中.
dispatch_group_async(serviceGroup,queue,^{
// some work here
});
這不是我們想要的,請(qǐng)求web服務(wù)我們需要的是可以馬上返回,然后每個(gè)請(qǐng)求中都有自己的completion block
.這樣,dispatch group會(huì)認(rèn)為我們的請(qǐng)求是'馬上完成'的.
第二種方法是手動(dòng)告訴dispatch group你要開始某個(gè)任務(wù)了.完成任務(wù)之后,你也需要手動(dòng)退出dispath group.
通過(guò)dispatch_group_enter()
,dispatch_group_leave()
兩個(gè)方法可以實(shí)現(xiàn)進(jìn)入
,退出
兩個(gè)動(dòng)作:
dispatch_group_enter(serviceGroup);
[configService startWithCompletion:^(ConfigResponse *results, NSError* error){
// Do something with the error or results
dispatch_group_leave(serviceGroup);
}];
每個(gè)enter
都必須有相應(yīng)的leave
,否則,你的dispatch group永遠(yuǎn)不會(huì)結(jié)束.在你要去請(qǐng)求一個(gè)web service的時(shí)候,你先enter
dispatch group,然后在返回的completion block中 leave
.
dispatch group完成方式
有兩種方式.
第一種是阻塞當(dāng)前的線程,直到dispatch group中的所有任務(wù)完成才會(huì)返回.
dispatch_group_wait(serviceGroup,DISPATCH_TIME_FOREVER);
// Won't get here until everything has finished
第二種不會(huì)阻塞當(dāng)前線程,馬上返回.
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Won't get here until everything has finished
});
在這里我們會(huì)使用第二種方法.
Putting it all together
下面我們來(lái)實(shí)現(xiàn)請(qǐng)求多個(gè)web service的方法:
-(void)fetchConfigurationWithCompletion:(void (^)(NSError* error))completion
{
// Define errors to be processed when everything is complete.
// One error per service; in this example we'll have two
__block NSError *configError = nil;
__block NSError *preferenceError = nil;
// Create the dispatch group
dispatch_group_t serviceGroup = dispatch_group_create();
// Start the first service
dispatch_group_enter(serviceGroup);
[self.configService startWithCompletion:^(ConfigResponse *results, NSError* error){
// Do something with the results
configError = error;
dispatch_group_leave(serviceGroup);
}];
// Start the second service
dispatch_group_enter(serviceGroup);
[self.preferenceService startWithCompletion:^(PreferenceResponse *results, NSError* error){
// Do something with the results
preferenceError = error;
dispatch_group_leave(serviceGroup);
}];
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
// Assess any errors
NSError *overallError = nil;
if (configError || preferenceError)
{
// Either make a new error or assign one of them to the overall error
overallError = configError ?: preferenceError;
}
// Now call the final completion block
completion(overallError);
});
}
你可以跟蹤每個(gè)請(qǐng)求的完成結(jié)果,然后做出相應(yīng)的動(dòng)作.