如何从 NSURLSessionDownloadTask downloadTaskWithRequest 获得响应

Posted

技术标签:

【中文标题】如何从 NSURLSessionDownloadTask downloadTaskWithRequest 获得响应【英文标题】:How to get a response from NSURLSessionDownloadTask downloadTaskWithRequest 【发布时间】:2015-09-11 18:48:34 【问题描述】:

先介绍一下背景: 应用程序应该从 AWS S3 服务器获取文件。为此,该过程的第一步是转到本地服务器并从中获取文件的名称和其他一些信息。在这一步之后,我们有一个完整的 URLMutableRequest

注意:我将 NSURLSession 设置为后台会话:

- (NSURLSession *)backgroundSession

    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"identifier"];
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    );
    return session;

这是从 AWS S3 服务器下载文件的任务:

对于这个任务我想使用代理在后台模式下运行。

@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
@property (nonatomic, strong) NSURLSession *defaultSession; 

self.defaultSession = [self backgroundSession];
self.downloadTask = [self.defaultSession downloadTaskWithRequest:request];
[self.downloadTask resume];

我如何从这个请求中获得响应?

Apple 文档说,在使用 backgroundSessionConfiguration 时,您不能将块作为 completionHandler。

【问题讨论】:

【参考方案1】:

如果有人想知道如何在下载完成之前获得下载响应,请尝试以下操作:改为启动 dataTask,获取响应,然后在需要时将 dataTask 转换为下载。

NSURLSessionTask *task = [session dataTaskWithRequest:request];
[task resume];

NSURLSessionDataDelegate

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler 
    // use response, convert data task to download task
    completionHandler(NSURLSessionResponseBecomeDownload);


- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask 
    // downloadTask converted from dataTask

NSURLSessionDownloadDelegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite 
    // update progress


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location 
    // copy downloaded file from location

【讨论】:

谢谢,这个想法真的很有帮助。【参考方案2】:

NSURLSessionDownloadTask 有一个 response 属性(它的基类的一部分,NSURLSessionTask),应该设置为响应。见here。

【讨论】:

那么,如果在我的描述中使用示例,如果我使用self.downloadTask.response,我应该能够从给定的请求中获得响应 是的。如果您持有对NSURLSessionDownloadTask 的引用,则可以在其完成后随时访问其response 属性。 如果您正在实现委托方法-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error,它将从当时传递给您的task 中获得。 如果您要处理类似 404 的问题,您需要查看 Roman B. 的答案,因为 downloadTask 对象的 response 属性不会这样做。 如果你做了一个 HTTP 请求,你可以按照developer.apple.com/documentation/foundation/… 将响应转换成一个 NSHTTPURLResponse 像这样` ((NSHTTPURLResponse*)downloadTask.response).statusCode`。【参考方案3】:

您需要在您的类中实现NSURLSessionDownloadDelegate 协议(因为您将会话委托指定为self)。

您应该查看文档以了解可用的方法,但您至少要实现以下内容:

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data

【讨论】:

我正在实现委托方法。我正在将文件从临时位置移动到目标位置并验证何时调用 URLSession:task:didCompleteWithError。但是如何从请求中得到响应 ??? =] 你的意思是http头和东西?检查@mean-dinosaur 答案,使用响应属性(您可能需要将其转换为NSHTTPURLResponse 好的!我需要将此响应转换为 NSString *downloadString = [[NSString alloc]initWithData:downloadData encoding:NSUTF8StringEncoding];initWithData 关于如何转换为 NSHTTPURLResponse 并获得 NSData 的任何建议??? @mean-恐龙 就数据而言,您到底想要什么?您认为响应(或您所说的响应)是或应该是什么? 如果您想要文件的内容(数据),那么您将使用委托方法获得它。如果您想要元数据(例如响应的 http 标头),请使用 response 属性。

以上是关于如何从 NSURLSessionDownloadTask downloadTaskWithRequest 获得响应的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从回收器适配器发送到片段 |如何从 recyclerview 适配器调用片段函数

如何从 Firebase 获取所有设备令牌?

如何直接从类调用从接口继承的方法?

如何从服务器获取和设置 android 中的 API(从服务器获取 int 值)?如何绑定和实现这个

如何从Mac从android studio中的fabric注销? [复制]

如何从设备中获取 PDF 文件以便能够从我的应用程序中上传?