很多时候我们在做网络请求的时候,往往要拿到数据后才能去处理进一步的操作。但是,AFNetworking
并没有同步的方法,那么我们应该怎么处理呢?
方法一:
- (void)getWeatherData
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block BOOL isSuccess = NO;
__block NSDictionary *json = nil;
[manager GET:@"http://www.weather.com.cn/data/sk/101010100.html"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject)
{
NSLog(@"加载成功 %@",responseObject);
isSuccess = YES;
if ([responseObject isKindOfClass:[NSDictionary class]]) {
json = responseObject;
}
dispatch_semaphore_signal(sem);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"加载失败 %@",error);
isSuccess = NO;
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
/* 回到主线程做进一步处理 */
if(isSuccess) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"请求成功" message:[NSString stringWithFormat:@"%@",json] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
}
});
});
}
方法二:
- (void)getWeatherData
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSCondition *condition = [[NSCondition alloc] init];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
__block BOOL isSuccess = NO;
__block NSDictionary *json = nil;
[manager GET:@"http://www.weather.com.cn/data/sk/101010100.html"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject)
{
NSLog(@"加载成功 %@",responseObject);
isSuccess = YES;
if ([responseObject isKindOfClass:[NSDictionary class]]) {
json = responseObject;
}
[condition lock];
[condition signal];
[condition unlock];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"加载失败 %@",error);
isSuccess = NO;
[condition lock];
[condition signal];
[condition unlock];
}];
[condition lock];
[condition wait];
[condition unlock];
dispatch_async(dispatch_get_main_queue(), ^{
/* 回到主线程做进一步处理 */
if(isSuccess) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"请求成功" message:[NSString stringWithFormat:@"%@",json] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
}
});
});
}
方法三:
- (NSDictionary *)getJsonData
{
NSString *url = [NSString stringWithFormat:@"请求的url字符串"];
/* 请求参数字典 */
NSMutableDictionary *requestParms = [[NSMutableDictionary alloc] init];
[requestParms setObject:@"value" forKey:@"key"];
AFJSONRequestSerializer *requestSerializer = [AFJSONRequestSerializer serializer];
NSMutableURLRequest *request = [requestSerializer requestWithMethod:@"POST" URLString:url parameters:requestParms error:nil];
/* 最终继承自 NSOperation,看到这个,大家可能就知道了怎么实现同步的了,也就是利用 NSOperation 来做的同步请求 */
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
AFHTTPResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializer];
[requestOperation setResponseSerializer:responseSerializer];
[requestOperation start];
[requestOperation waitUntilFinished];
/* 请求结果 */
NSDictionary *result = (NSDictionary *)[requestOperation responseObject];
if (result != nil) {
return result;
}
return nil;
}
小结
使用上面任意一种方法都可以解决AFNetworking同步请求的操作。需要注意的是,前两种方法中请求要放在异步线程执行,否则会死锁,在请求结束后再回到主线程执行。
上半部分内容转载自:AFNtworking同步请求解决方法
作者:jixuqianxing
Postscript:
- 使用AFNetworking时,程序会先执行网络请求,后直接往前走到方法的return,在之后才会执行完block内部的内容,故而需要方法的返回值时需慎重;
- 第一种阻塞线程实现网络请求同步的做法测试了下发现无效,分析原因可能为先进行网络请求,然后直接执行到
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
,此时未接收到dispatch_semaphore_signal(sem);
的信息,而当该语句执行的时候该方法已经运行结束,故无法接着执行return操作 - 后面方法未测,目前先采用同步网络请求进行操作,后面有时间再行测试
- 如有遗漏错误之处欢迎指正