我有一个iOS应用程序,它使用NSOperationQueue、NSOperations和AFNetworking 2.1.0来向服务器发送请求。-[NSOperation main]方法看起来类似于:
- (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冲突?
发布于 2014-04-14 21:57:23
不知道这件事是否还和你有关,但这件事让我整晚都在胡思乱想。原来你只是部分地回答了问题中的问题。
结果是,如果
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: ...
}或者,是的,您可以只在主线程上执行任务创建。但对于一些项目来说,事情并不总是那么简单。
发布于 2014-02-27 00:28:33
我会将一个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];https://stackoverflow.com/questions/22054823
复制相似问题