今天遇到了一個(gè)有關(guān)同步網(wǎng)絡(luò)請(qǐng)求的需求是這樣的,App中所有網(wǎng)絡(luò)請(qǐng)求都需要使用一個(gè)BaseUrl作為前綴,這個(gè)前綴需要一個(gè)專(zhuān)門(mén)的配置接口去請(qǐng)求獲取??紤]到如果在App啟動(dòng)的時(shí)候異步請(qǐng)求配置接口獲取BaseUrl,并不能保證APP首頁(yè)發(fā)起的網(wǎng)絡(luò)請(qǐng)求前綴是正確的BaseUrl,于是我考慮采用同步請(qǐng)求的方法確保BaseUrl的獲取。
因?yàn)槲覀冊(cè)陂_(kāi)發(fā)App的時(shí)候常用的網(wǎng)絡(luò)框架就是AFNetWorking ,于是我首先想到了使用AFNetworking結(jié)合信號(hào)量的方式來(lái)實(shí)現(xiàn)這個(gè)同步請(qǐng)求,代碼如下:
//更新系統(tǒng)配置,獲取BaseUrl的方法,在App啟動(dòng)時(shí)候調(diào)用
- (void)updateAppSystemConfig{
//1.創(chuàng)建信號(hào)量,阻塞了主線程
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//這里省略了AFN請(qǐng)求網(wǎng)絡(luò)的方法,成功和失敗的回調(diào)里都需要調(diào)用下面的代碼
//2.網(wǎng)絡(luò)請(qǐng)求結(jié)束,發(fā)送通知信號(hào)
//dispatch_semaphore_signal(semaphore);
});
// 3.發(fā)送等待信號(hào)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//同步請(qǐng)求配置結(jié)束之后,結(jié)束阻塞
}
但是上述的代碼卻無(wú)形中造成了死鎖的問(wèn)題。這是因?yàn)槲覀兪褂肎CD的信號(hào)量首先阻塞了主線程,而是在異步線程里使用了AFN請(qǐng)求網(wǎng)絡(luò),由于AFN自身的原因,無(wú)論還是成功還是失敗網(wǎng)絡(luò)請(qǐng)求的響應(yīng)總是要回到主線程中進(jìn)行操作,但是此時(shí)的主線程卻是阻塞的,所以就互相等待就造成了死鎖。
然后我就采用了系統(tǒng)自帶的網(wǎng)絡(luò)請(qǐng)求的方法來(lái)解決這個(gè)問(wèn)題,代碼如下:
//更新系統(tǒng)配置,獲取BaseUrl的方法,在App啟動(dòng)時(shí)候調(diào)用
- (void)updateAppSystemConfig{
//1.創(chuàng)建信號(hào)量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//開(kāi)始異步請(qǐng)求操作
NSURL*url=[NSURL URLWithString:Path_app_config];
//創(chuàng)建請(qǐng)求命令,并設(shè)置緩存策略
NSURLRequest *request= [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
//創(chuàng)建會(huì)話對(duì)象通過(guò)單例方法實(shí)現(xiàn)
NSURLSession *session=[NSURLSession sharedSession];
//執(zhí)行會(huì)話的任務(wù)
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"請(qǐng)求配置失敗了");
}else{
NSDictionary *responData=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if ([responData[@"errcode"] integerValue] ==QQMFRequest_OK) {
//網(wǎng)絡(luò)請(qǐng)求成功,將新配置更新到本地,可以從配置數(shù)據(jù)中得到BaseUrl
[AppConfigTools updateAppConfigWithData:responData];
}
}
// 2.在網(wǎng)絡(luò)請(qǐng)求結(jié)束后發(fā)送通知信號(hào)
dispatch_semaphore_signal(semaphore);
}];
//開(kāi)始執(zhí)行任務(wù)
[task resume];
});
// 3.發(fā)送等待信號(hào)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//同步請(qǐng)求配置結(jié)束之后,結(jié)束阻塞
}
這里使用的是系統(tǒng)自帶的網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求系統(tǒng)配置BaseUrl的網(wǎng)絡(luò)請(qǐng)求是在異步線程里實(shí)現(xiàn)的,而且網(wǎng)絡(luò)請(qǐng)求完成之后發(fā)出信號(hào)量的通知也是在異步線程中,這樣就不會(huì)造成了阻塞。也實(shí)現(xiàn)了同步等待的需求。