首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >非唯一NSURLSessionDataTask taskIdentifiers

非唯一NSURLSessionDataTask taskIdentifiers
EN

Stack Overflow用户
提问于 2014-02-26 22:27:19
回答 2查看 1.2K关注 0票数 4

我有一个iOS应用程序,它使用NSOperationQueue、NSOperations和AFNetworking 2.1.0来向服务器发送请求。-[NSOperation main]方法看起来类似于:

代码语言:javascript
复制
- (void)main {
  AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager sharedSessionManager];
  [sessionManager GET:@"url"
           parameters:nil
              success:^(NSURLSessionDataTask *task, id responseObject) {
                NSLog(@"Success");
              }
              failure:^(NSURLSessionDataTask *task, NSError *error) {
                NSLog(@"Failure");
              }
  ];
}

我注意到,当创建多个操作并快速地将其添加到NSOperationQueue时,对特定操作的回调永远不会被执行。我潜入AFNetworking试图找出原因。我最后进入了-[AFURLSessionManager dataTaskWithRequest:completionHandler],它看起来像:

代码语言:javascript
复制
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];

    AFURLSessionManagerTaskDelegate *delegate = [AFURLSessionManagerTaskDelegate delegateForManager:self completionHandler:completionHandler];
    [self setDelegate:delegate forTask:dataTask];

    return dataTask;
}

在创建dataTask之后,我立即添加了一个日志语句:

代码语言:javascript
复制
NSLog(@"Task with id %@ created for %@ on queue %@", @(dataTask.taskIdentifier), request.URL.path, dispatch_get_current_queue());

日志揭示了这个问题:

代码语言:javascript
复制
2014-02-26 14:11:25.071 App[50094:6a2f] Task with id 15 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:25.071 App[50094:460f] Task with id 16 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>

2014-02-26 14:11:26.274 App[50094:6a2f] Task with id 18 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:26.274 App[50094:6c17] Task with id 17 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>

2014-02-26 14:11:27.546 App[50094:6307] Task with id 20 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:27.546 App[50094:6b17] Task with id 19 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>

2014-02-26 14:11:28.705 App[50094:6b17] Task with id 21 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:28.705 App[50094:6307] Task with id 21 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>

2014-02-26 14:11:32.091 App[50094:6307] Task with id 22 created for /url2 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>
2014-02-26 14:11:32.091 App[50094:6b17] Task with id 23 created for /url1 on queue <OS_dispatch_queue: NSOperationQueue 0xc4b8560[0xc4b8ac0]>

注意,日志中的第四组具有相同的taskIdentifier,这是AFNetworking通过委托将任务与其回调相关联的方法。

如果我强迫NSOperations在主队列上运行,那么我就无法重新创建这个问题-- taskIdentifier总是唯一的。

以前有人见过这样的东西吗?我是否需要确保-[NSURLSession dataTaskWithRequest:]只在主线程上运行,以避免taskIdentifier冲突?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-14 21:57:23

不知道这件事是否还和你有关,但这件事让我整晚都在胡思乱想。原来你只是部分地回答了问题中的问题。

结果是,如果

代码语言:javascript
复制
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];

异步运行,则NSURLSession实例将为不同任务分配相同的taskIdentifier的可能性很小。

在没有分叉AFNetworking和同步所有dataTaskWithRequest:方法的情况下,我可以通过两种方法来解决这个突出问题。

如果您不需要从此方法返回的NSURLSessionTask,那么最好的方法是创建您自己的调度队列,以及您想使用会话管理器发出的任何请求,您只需异步地将其发送到该队列,如下所示:

代码语言:javascript
复制
static dispatch_queue_t my_queue;
my_queue = dispatch_queue_create("MyQueueName", DISPATCH_QUEUE_CONCURRENT);

// ... Later, that very same day

dispatch_async(my_queue, ^{
    // [sessionManager GET: ...
});

但是,这个方法的唯一问题是,它似乎都是在同一个操作队列上执行的,所以这种方法在您的情况下可能行不通。另一种方法(我就是这样做的)实际上是比较简单的。只需在AFURLSessionManager上同步,这样dataTaskWithRequest:的调用就只能像这样同步地发生:

代码语言:javascript
复制
@synchronized(sessionManager) {
    // [sessionManager GET: ... 
}

或者,是的,您可以只在主线程上执行任务创建。但对于一些项目来说,事情并不总是那么简单。

票数 3
EN

Stack Overflow用户

发布于 2014-02-27 00:28:33

我会将一个NSURLSessionDataTask排队到您的AFURLSessionManager,而不是直接发出GET请求。会话管理器旨在抽象NSURLSession的功能。

示例:

代码语言:javascript
复制
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSURL *URL = [NSURL URLWithString:@"http://example.com/testapi.php"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"error!");
        } else {
            NSLog(@"task successful!");
        }
    }];
    [dataTask resume];
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22054823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档