之前使用AFN etWorking这个库来做网络请求,一直都是做的异步的,突然有需求需要改成同步的,当时从网上找了一些方法,说使用信号量来做,但是尝试了一些,都不对,最后由于时间关系,同步请求改为了系统的同步请求来实现了需求。后面仔细的去查了一下,原来信号量使用的不对,特此记录一下。
1:先看看系统自带的同步请求是如何发送的
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:BaseUrl(AppLogin)]];
//设置请求方式也POST(默认是GET)
request.timeoutInterval = 10;
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[parameters dataUsingEncoding:NSUTF8StringEncoding]];
//同步方式连接服务器
NSData *responseObject = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *error;
if (responseObject){
NSString *responseStr = [[ NSString alloc]initWithData:responseObject
encoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[responseStr
dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error] ;
success(json);
}else {
failure(error);
}
2:按照网上提供的方法,自己使用信号量错误的做法,下面这段代码是写在主线程里面的。
NSString *url = @"http://dev.autocamel.com:8095/driver-0.0.1/oss/policy";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(@"1");
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[manager POST:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task,
id _Nullable responseObject) {
NSLog(@"%@",responseObject);
NSLog(@"success");
dispatch_semaphore_signal(semaphore);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"fail");
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@"3");
分析下这段代码,创建了值为0的信号量,按照我们需要的意思,由于是异步请求,所以程序会直接运行到dispatch_semaphore_wait这个方法,由于信号量为0,并且等待时间为永久等待,所以目前不会执行NSLog(@"3"),等待信号量>0才会打印3,按照我们想的,异步请求返回后,执行回调block里面的dispatch_semaphore_signal,是信号量+1,之前会打印“success”或者“fail”,最后信号量>0,也会打印3,但实际我们看一下打印的结果,只打印了第一句NSLog("1"),为什么后面的都没有打印呢?
我们看一下AFNetWorking的源代码,我们这个请求完成后,请求结束后会执行
代理会执行下面的方法, 仔细看一下下面方法,会看到下面的所有的block默认都是在主线程执行的
应为主线程已经被信号量堵塞了,所以这个地方的成功或者是失败的回调都不可能在主线程执行,所以信号量也不可能>0,就会永远的阻塞下去,这就说明了为什么只打印了1,后面的都不会打印。
所以,修改的方法通过看源码就已经出来了,回调的block的completionGroup是没有赋值的,所以默认才会在主线程执行回调,只需要在开始的时候,给一个子线程就可以解决这个问题了
初始化的时候加上下面面一句话就可以了