Code
static NSString * const R1_START = @"第一個(gè)請求開始";
static NSString * const R1_END = @"第一個(gè)請求完成";
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self requestOneWithSuccessBlock:^{
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"done");
}
- (void) requestOneWithSuccessBlock:(void(^)(void))successBlock {
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"application/zip", @"text/json", @"text/javascript", @"text/html", @"text/plain", nil];
NSLog(@"%@",R1_START);
[sessionManager GET:@"http://www.weather.com.cn/data/cityinfo/101190408.html" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"%@",R1_END);
if (successBlock) {
successBlock();
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
Code Analysis
創(chuàng)建信號量
semaphore發(fā)起請求
信號量等待,阻塞主線程的執(zhí)行。主線程等待信號增加。
請求的回調(diào)方法在主線程執(zhí)行,所以等待主線程向下執(zhí)行。然后釋放信號。
由于這個(gè)請求并沒有指定completionQueue,所以它的回調(diào)方法在主線程執(zhí)行,然而此時(shí)主線程在等待semaphore,而semaphore的增加又需要主線程繼續(xù)向下執(zhí)行到回調(diào)方法才會執(zhí)行到。從而造成死鎖情況。
AFNetworking在沒有指定completionQueue的時(shí)候,回調(diào)方法是在主線程執(zhí)行
解決方式
不要將信號的等待和信號的釋放放到同一條串行隊(duì)列中
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
sessionManager.completionQueue = dispatch_get_global_queue(0, 0);
通過AFHttpSessionManager的completionQueue指定網(wǎng)絡(luò)請求的回調(diào)方法的執(zhí)行隊(duì)列。這樣,信號的釋放放入到了子線程中。
主線程信號量會保持等待。而回調(diào)方法是在另一條線程執(zhí)行的。不會受到主線程的影響。
請求回來之后,回調(diào)方法執(zhí)行,信號量釋放
主線程接收到信號量,解除阻塞。
注意點(diǎn)
使用信號量,盡量避免在主線程,它會阻塞主線程,導(dǎo)致卡頓問題
當(dāng)通過信號量控制網(wǎng)絡(luò)請求時(shí),一定避免信號的等待和釋放在同一條串行隊(duì)列中。會導(dǎo)致死鎖問題。