如何在没有完成块的NSURLSession中获取服务器响应数据

我正在使用NSURLSession进行背景图片上传。 并根据上传的图像我的服务器给我的回应,我确实相应地改变我的应用程序。 但是当我的应用程序在后台上传图像时,我无法得到我的服务器响应,因为没有完成块。

有没有办法获得响应,而不使用NSURLUploadTask完成块?

这是我的代码:

  self.uploadTask = [self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"returnString : %@",returnString); NSLog(@"error : %@",error); }]; [self.uploadTask resume]; 

但是我得到这个错误

由于未捕获的exception“NSGenericException”而终止应用程序,理由是:“后台会话中不支持完成处理程序块。 使用委托代替。

但是,如果我不能使用完成处理程序比我应该如何得到服务器响应。 它说使用委托,但我找不到任何委托方法,可以给我服务器响应。

一些想法:

首先,使用delegate实例化会话,因为后台会话必须有一个委托:

 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kSessionIdentifier]; self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; 

其次,在没有完成处理程序的情况下实例化NSURLSessionUploadTask ,因为添加到后台会话的任务不能使用完成块。 另外请注意,我使用的是一个文件的URL而不是NSData

 NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:fileURL]; [task resume]; 

三是落实有关的委托方式。 至less,这可能看起来像:

 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSMutableData *responseData = self.responsesData[@(dataTask.taskIdentifier)]; if (!responseData) { responseData = [NSMutableData dataWithData:data]; self.responsesData[@(dataTask.taskIdentifier)] = responseData; } else { [responseData appendData:data]; } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { NSLog(@"%@ failed: %@", task.originalRequest.URL, error); } NSMutableData *responseData = self.responsesData[@(task.taskIdentifier)]; if (responseData) { // my response is JSON; I don't know what yours is, though this handles both NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil]; if (response) { NSLog(@"response = %@", response); } else { NSLog(@"responseData = %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]); } [self.responsesData removeObjectForKey:@(task.taskIdentifier)]; } else { NSLog(@"responseData is nil"); } } 

请注意,以上是利用以前实例化的NSMutableDictionary名为NSMutableDictionary (因为,我很懊恼,这些“任务”委托方法是在“会话”级别完成)。

最后,你要确保定义一个属性来存储handleEventsForBackgroundURLSession提供的completionHandler

 @property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void); 

显然,让你的应用程序委托响应handleEventsForBackgroundURLSession ,保存下面的URLSessionDidFinishEventsForBackgroundURLSession方法中使用的URLSessionDidFinishEventsForBackgroundURLSession

 - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { // This instantiates the `NSURLSession` and saves the completionHandler. // I happen to be doing this in my session manager, but you can do this any // way you want. [SessionManager sharedManager].backgroundSessionCompletionHandler = completionHandler; } 

然后确保当后台会话完成时,您的NSURLSessionDelegate在主线程上调用此处理程序:

 - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { if (self.backgroundSessionCompletionHandler) { dispatch_async(dispatch_get_main_queue(), ^{ self.backgroundSessionCompletionHandler(); self.backgroundSessionCompletionHandler = nil; }); } } 

只有在后台完成某些上传时才会调用此function。

正如你所看到的那样,有几个可移动的部分,但这基本上是需要的。