AFNetworing同步网络请求?

2018-04-24 14:43:05 浏览数 (3)

今天遇到了一个有关同步网络请求的需求是这样的,App中所有网络请求都需要使用一个BaseUrl作为前缀,这个前缀需要一个专门的配置接口去请求获取。考虑到如果在App启动的时候异步请求配置接口获取BaseUrl,并不能保证APP首页发起的网络请求前缀是正确的BaseUrl,于是我考虑采用同步请求的方法确保BaseUrl的获取。

因为我们在开发App的时候常用的网络框架就是AFNetWorking ,于是我首先想到了使用AFNetworking结合信号量的方式来实现这个同步请求,代码如下:

代码语言:javascript复制
//更新系统配置,获取BaseUrl的方法,在App启动时候调用
- (void)updateAppSystemConfig{
    //1.创建信号量,阻塞了主线程
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //这里省略了AFN请求网络的方法,成功和失败的回调里都需要调用下面的代码
        //2.网络请求结束,发送通知信号
        //dispatch_semaphore_signal(semaphore);
    });
    // 3.发送等待信号
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //同步请求配置结束之后,结束阻塞
}

但是上述的代码却无形中造成了死锁的问题。这是因为我们使用GCD的信号量首先阻塞了主线程,而是在异步线程里使用了AFN请求网络,由于AFN自身的原因,无论还是成功还是失败网络请求的响应总是要回到主线程中进行操作,但是此时的主线程却是阻塞的,所以就互相等待就造成了死锁。

然后我就采用了系统自带的网络请求的方法来解决这个问题,代码如下:

代码语言:javascript复制
//更新系统配置,获取BaseUrl的方法,在App启动时候调用
- (void)updateAppSystemConfig{
    //1.创建信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //开始异步请求操作
        NSURL*url=[NSURL URLWithString:Path_app_config];
        //创建请求命令,并设置缓存策略
        NSURLRequest *request= [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
        //创建会话对象通过单例方法实现
        NSURLSession *session=[NSURLSession sharedSession];
        //执行会话的任务
        NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (error) {
                NSLog(@"请求配置失败了");
            }else{
                NSDictionary *responData=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
                if ([responData[@"errcode"] integerValue] ==QQMFRequest_OK) {
                    //网络请求成功,将新配置更新到本地,可以从配置数据中得到BaseUrl
                    [AppConfigTools updateAppConfigWithData:responData];
                }
            }
            // 2.在网络请求结束后发送通知信号
            dispatch_semaphore_signal(semaphore);
        }];
        //开始执行任务
        [task resume];
    });
    // 3.发送等待信号
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //同步请求配置结束之后,结束阻塞
}

这里使用的是系统自带的网络请求,请求系统配置BaseUrl的网络请求是在异步线程里实现的,而且网络请求完成之后发出信号量的通知也是在异步线程中,这样就不会造成了阻塞。也实现了同步等待的需求。

0 人点赞