ios 如何在没有完成块的情况下在 NSURLSession 中获取服务器响应数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23731043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get server response data in NSURLSession without completion block
提问by Rob
I am using NSURLSessionfor background image uploading. And according to uploaded image my server gives me response and I do change in my app accordingly. But I can't get my server response when my app uploading image in background because there is no completion block.
我正在使用NSURLSession背景图片上传。根据上传的图片,我的服务器给了我响应,我会相应地更改我的应用程序。但是当我的应用程序在后台上传图像时,我无法获得服务器响应,因为没有完成块。
Is there way to get response without using completion block in NSURLUploadTask?
有没有办法在不使用完成块的情况下获得响应NSURLUploadTask?
Here is my code :
这是我的代码:
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];
But i got this error..
但我得到了这个错误..
Terminating app due to uncaught exception 'NSGenericException', reason: 'Completion handler blocks are not supported in background sessions. Use a delegate instead.'
由于未捕获的异常“NSGenericException”而终止应用程序,原因:“后台会话中不支持完成处理程序块。改用委托。
But if I can't use completion handler than how should I get the server response. It says use delegate but I can't find any delegate method which can gives me server response.
但是如果我不能使用完成处理程序,那么我应该如何获得服务器响应。它说使用委托,但我找不到任何可以为我提供服务器响应的委托方法。
回答by Rob
A couple of thoughts:
一些想法:
First, instantiate your session with a delegate, because background sessions must have a delegate:
首先,使用 a 实例化您的会话delegate,因为后台会话必须有一个委托:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:kSessionIdentifier];
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
Second, instantiate your NSURLSessionUploadTaskwithout a completion handler, because tasks added to a background session cannot use completion blocks. Also note, I'm using a file URL rather than a NSData:
其次,在NSURLSessionUploadTask没有完成处理程序的情况下实例化您,因为添加到后台会话的任务不能使用完成块。另请注意,我使用的是文件 URL 而不是NSData:
NSURLSessionTask *task = [self.session uploadTaskWithRequest:request fromFile:fileURL];
[task resume];
Third, implement the relevant delegate methods. At a minimum, that might look like:
第三,实现相关的委托方法。至少,这可能看起来像:
- (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");
}
}
Note, the above is taking advantage of a previously instantiated NSMutableDictionarycalled responsesData(because, much to my chagrin, these "task" delegate methods are done at the "session" level).
请注意,以上是利用先前实例化的NSMutableDictionary调用responsesData(因为令我懊恼的是,这些“任务”委托方法是在“会话”级别完成的)。
Finally, you want to make sure to define a property to store the completionHandlerprovided by handleEventsForBackgroundURLSession:
最后,您要确保定义一个属性来存储completionHandler提供的handleEventsForBackgroundURLSession:
@property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void);
And obviously, have your app delegate respond to handleEventsForBackgroundURLSession, saving the completionHandler, which will be used below in the URLSessionDidFinishEventsForBackgroundURLSessionmethod.
显然,让您的应用程序委托响应handleEventsForBackgroundURLSession,保存completionHandler,这将在下面的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;
}
And then make sure your NSURLSessionDelegatecalls this handler on the main thread when the background session is done:
然后确保NSURLSessionDelegate在后台会话完成后在主线程上调用此处理程序:
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
if (self.backgroundSessionCompletionHandler) {
dispatch_async(dispatch_get_main_queue(), ^{
self.backgroundSessionCompletionHandler();
self.backgroundSessionCompletionHandler = nil;
});
}
}
This is only called if some of the uploads finished in the background.
仅当某些上传在后台完成时才会调用。
There are a few moving parts, as you can see, but that's basically what's entailed.
正如您所看到的,有一些活动部分,但这基本上是必需的。

