【问题标题】:Best practice to replace a synchronous NSURLConnection with NSURLSession用 NSURLSession 替换同步 NSURLConnection 的最佳实践
【发布时间】:2016-06-15 16:53:29
【问题描述】:

作为

NSURLConnection sendSynchronousRequest:returningResponse:error:&connectionError

已弃用,我将不得不替换我很久以前写的 Importer。

导入器执行以下操作:

  1. 它从 API-A 获取数据。那里的数据可以在多个页面上。
  2. 它使用来自第一次提取(也是多页)的数据从 API-B 查询数据并合并
  3. API-B 查询的结果将与 API-A 中的数据合并

我通过后台操作实现了这一点,其中我为每个 API 使用方法,如果请求有多个页面,则递归调用。

但由于 NSURLSession 不支持同步请求,我目前只看到有大量开销(例如 iVars)控制完成块中调用的内容(例如下一页或开始查询 API-B)的选项。

那么,将它带到 NSURLSession 的优雅解决方案是什么。

注意:只是为了确保,我之前的解决方案根本不会阻塞主线程。但在当时,这是控制两个来源合并的最简单方法。

【问题讨论】:

  • 我不明白为什么你需要同步调用。按照正常的约定,Webservicecalls 总是应该是异步的。如果你想让用户等待然后..放置一个显示设备正在获取结果的 HUD/ActivityIndi​​cator.. 同步调用任何 web api 不是一个好主意。所以按照我的建议通过异步调用
  • 正如我上面提到的,我在后台线程上进行导入,因此既没有阻塞 UI,也没有可见的进度指示器。我使用同步方法的原因(同样,我使用它的方式并没有阻塞任何东西!)是我必须等待来自未知数量请求的未知数量的数据。并且同步方法让我能够更好地处理这一点,而不是保持大量开销来处理异步请求。

标签: ios nsurlconnection nsurlsession


【解决方案1】:

这个答案不应该是最佳实践。这对我来说很实用。

面对在后台执行一堆同步请求并且执行顺序很重要的情况,我最终使用了以下内容:

SyncRequestSender.h

#import <Foundation/Foundation.h>

@interface SyncRequestSender : NSObject

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(NSURLResponse **)response
                             error:(NSError **)error;

@end

SyncRequestSender.m

#import "SyncRequestSender.h"

@implementation SyncRequestSender

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(NSURLResponse **)response
                             error:(NSError **)error
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);


    NSError __block *err = NULL;
    NSData __block *data;
    NSURLResponse __block *resp;

    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:^(NSData* _data, NSURLResponse* _response, NSError* _error) {
        resp = _response;
        err = _error;
        data = _data;
        dispatch_group_leave(group);

    }] resume];

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    if (response)
    {
        *response = resp;
    }
    if (error)
    {
        *error = err;
    }

    return data;
}

@end

【讨论】:

  • 我认为使用dispatch_semaphore_wait 更好。
  • @KleinMioke 考虑使用它,但由于某种原因决定与调度组一起玩。
【解决方案2】:

这是AFNetworking中的一个例子,它展示了如何等待一个异步任务。

- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
            tasks = dataTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
            tasks = uploadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
            tasks = downloadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
            tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
        }

        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    return tasks;
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    相关资源
    最近更新 更多