NSURLSession,数据任务转换为下载任务后,后台无法下载

Posted

技术标签:

【中文标题】NSURLSession,数据任务转换为下载任务后,后台无法下载【英文标题】:NSURLSession, after the data task is converted to download task, it can't download in background 【发布时间】:2016-05-07 16:36:18 【问题描述】:

如果我运行以下代码并让应用程序在后台运行,下载仍在继续。最后,当下载完成后,我可以得到正确的回调。

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SessionProperties.identifier)
let backgroundSession = NSURLSession(configuration: configuration, delegate: self.delegate, delegateQueue: nil)

let url = NSURLRequest(URL: NSURL(string: data[1])!)
let downloadTask = backgroundSession.downloadTaskWithRequest(url)
    downloadTask.resume()

但是我有一个要求,就是我要判断服务器返回给我的是什么,如果是json,我不做下载,所以我想先获取响应头,然后如果需要要下载,我将数据任务更改为下载任务,所以我按照以下代码进行

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SessionProperties.identifier)
let backgroundSession = NSURLSession(configuration: configuration, delegate: self.delegate, delegateQueue: nil)

let url = NSURLRequest(URL: NSURL(string: data[1])!)
//I change the downloadTaskWithRequest to dataTaskWithRequest
let downloadTask = backgroundSession.dataTaskWithRequest(url)
downloadTask.resume()

然后我可以在回调中获取响应头,如果需要下载文件,我可以将数据任务改为下载任务,如下

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) 
    if let response = response as? NSHTTPURLResponse 
        let contentType = response.allHeaderFields["Content-Type"] as! String
        if contentType == "image/jpeg" 
            //change the data task to download task
            completionHandler(.BecomeDownload)
            return
        
    
    completionHandler(.Allow)


到目前为止一切顺利。当我在前台运行应用程序时,效果和我想的一样。但是应用在后台运行后,下载停止,然后当我打开应用时,控制台显示“与后台传输服务的连接丢失”。

我以为苹果很聪明,他给了我们很多有用的回调,但是现在,我不知道我哪里错了,我也看到了关于 AFNetworking 和 Alamofire 的源代码,但我没有找到指的东西。

我也认为这是一个普遍的要求,但我在互联网上找不到任何有用的信息,这太奇怪了。

所以希望你能帮助我,谢谢十亿。

【问题讨论】:

正如苹果的一位员工所说,这是操作系统的错误。所以我就这样退出了。我现在做的新方法是创建一个下载任务。数据下载完成后,判断响应头,如果数据是图片,则将数据转移到其他地方,如果是json,则从tmp文件中读取并做引用处理。 【参考方案1】:

启用后台模式 Xcode->Target->Capabilities->On Background Mode 并选择 Background Fetch 选项。

【讨论】:

【参考方案2】:

我看到的主要问题是您调用了两次completionHandler。您需要像这样从内容类型条件中返回:

if contentType == "image/jpeg" 
    //change the data task to download task
    completionHandler(.BecomeDownload)
    return

否则,您似乎正确地使用了逻辑。希望对您有所帮助。

【讨论】:

感谢您的回答,很抱歉我用错误的逻辑复制了代码。面对现实,即使我在“didReceiveResponse”回调中只写了一行代码——“completionHandler(.BecomeDownload)”。我得到了同样的错误。我在github上做了一个demo,如果方便的话,请下载运行,开始下载的时候点击home键,然后再打开app,就会看到报错。 github.com/tuchangwei/data_task_convert_to_download_task【参考方案3】:

从您自己的回答中可以看出问题所在。这不是错误,您根本无法将数据任务用于后台传输,而只是下载任务。

Here 是正确的完整答案。

【讨论】:

谢谢,从tmp文件中读取数据是判断我下载的是媒体文件还是json数据的好方法。

以上是关于NSURLSession,数据任务转换为下载任务后,后台无法下载的主要内容,如果未能解决你的问题,请参考以下文章

NSURLSession 后台断点下载

使用 NSURLSession 如何在取消下载任务时获取接收到的数据或临时文件位置

URLSession 下载任务委托仅在所有任务完成后调用

NSURLSession,多数据任务,completionHandler

NSURLSession 后台任务:避免重复

NSURLSession 下载任务 - Xamarin iOS F#