2014-02-26 44 views
4

我有一個iOS應用程序正在使用NSOperationQueue,NSOperations和AFNetworking 2.1.0將請求發送到服務器。該-[NSOperation main]方法看起來是這樣的:非唯一的NSURLSessionDataTask任務標識符

- (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],它看起來像:

- (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創建後右:

NSLog(@"Task with id %@ created for %@ on queue %@", @(dataTask.taskIdentifier), request.URL.path, dispatch_get_current_queue()); 

日誌揭示了問題:

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碰撞?

回答

1

不知道這仍然是與你有關的或沒有,但這個確切的事情讓我敲我的腦袋周圍所有的夜晚。原來你部分回答了你的問題。

,因爲它會變成,如果

NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request]; 

是異步運行,再有就是小機會的NSURLSession實例將分配相同的taskIdentifier不同的任務。

沒有分叉AFNetworking和同步所有的dataTaskWithRequest:方法,那麼有兩種方法可以解決這個問題。

如果你不需要從這個方法返回NSURLSessionTask那麼最好的辦法就是製作你自己的調度隊列,並且你想用你的會話管理器創建任何請求,然後將它異步地發送到該隊列中,如下所示:

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:調用永遠只能同步發生像這樣:

@synchronized(sessionManager) { 
    // [sessionManager GET: ... 
} 

或者,是的,你可能只是做在主線程任務創作。但對於一些項目來說,並不總是那麼簡單。

0

我會排隊NSURLSessionDataTask到您的AFURLSessionManager,而不是試圖直接進行GET請求。會話管理器旨在提取NSURLSession的功能。

例子:

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

這幾乎就是 - [AFHTTPSessionManager GET:parameters:success:failure:]正在爲我做。見[這裏](https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFHTTPSessionManager.m#L110-L132) – goddardcm