背景
- 当H5调用OC的时候,默认是在主线程的,如果H5调用后,需要原生返回数据,而原生获取数据又是个耗时的异步操作就会有问题,比如OC是一个网络请求,那就需要等原生请求返回后,再返给H5。
- 当然可以在网络请求返回的时候,调用H5的一个方法,但是觉得这样的实现方式有点low,所以还是想把网络请求改成同步,这样就可以解决这个问题了。
使用信号量来实现
- 信号量的介绍
正常的使用顺序是先降低然后再提高,这两个函数通常成对使用。
// 创建一个信号,value:信号量
dispatch_semaphore_create(<#long value#>)
// 使某个信号的信号量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)
// 某个信号进行等待或等待降低信号量 timeout:等待时间,永远等待为 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
- 实现
- (NSDictionary *)httpRequest {
__block NSDictionary *response = @{};
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", nil];
NSString *url = @"http:www.baidu.com";
[manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
response = responseObject;
NSLog(@"");
dispatch_semaphore_signal(sem);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return response;
}
但是发现不工作,表象就是线程卡住了。
后来翻看AFNetworking源码发现NSURLSessionTaskDelegate的代理方法中
成功的回调是在主线程中执行的,但是此时的主线程已经被阻塞了,所以导致失败。
- 解决办法就是给manager一个自己的线程
- (NSDictionary *)httpRequest {
__block NSDictionary *response = @{};
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 给manager一个自己的线程
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", nil];
NSString *url = @"http:www.baidu.com";
[manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
response = responseObject;
NSLog(@"");
dispatch_semaphore_signal(sem);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return response;
}