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 NSURLSession
for 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 NSURLSessionUploadTask
without 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 NSMutableDictionary
called 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 completionHandler
provided 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 URLSessionDidFinishEventsForBackgroundURLSession
method.
显然,让您的应用程序委托响应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 NSURLSessionDelegate
calls 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.
正如您所看到的,有一些活动部分,但这基本上是必需的。