1

If I run the following code and let the app in background, the download is still continuing. Finally, when the download is finished, I can get the right callback.

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()

But I have a requirement, that is I have to judge what the server returns to me, if it is a json, I don't do the download, so I want to get the response header first, then if it needs to download, I change the data task to download task, so I did as the following code

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()

Then I can get the response header in the callback, and if it needs to download file, I can change the data task to download task, as following

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)

}

So far so good. When I run the app in the foreground, the effect is like what I thought. But after the app runs in background, the download is stoped, then when I open the app, the console says "Lost connection to background transfer service".

I thought Apple is so smart, he gives us many useful callbacks, but now, I didn't know where I am wrong, and I also see the source code about the AFNetworking and Alamofire, but I didn't find the referring thing.

I also think it is a common requirement, but I can't find any helpful information on the internet, it is too odd.

So hope you can help me out, thanks a billion.

Changwei
  • 672
  • 1
  • 5
  • 16
  • 1
    As one staff of Apple said, it is a bug from OS. So I quit this way. The new way I do it now is to create a download task. After the data is downloaded, to judge the response header, if the data is an image, transfer the data to other place, if it is a json, read it from the tmp file and do the referring handling. – Changwei May 14 '16 at 07:24

3 Answers3

0

Enable Background Mode in Xcode->Target->Capabilities->On Background Mode and select the option Background Fetch.

shiju86.v
  • 667
  • 5
  • 10
0

The main issue I see is that you're calling the completionHandler twice. You need to return out of your content-type conditional like so:

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

Otherwise it appears that you are using the logic correctly. Hope that helps.

cnoon
  • 16,575
  • 7
  • 58
  • 66
  • Thanks for your answer, I am sorry I copied the code with wrong logic. In face, even though I only write one line code - "completionHandler(.BecomeDownload)" in the "didReceiveResponse" callback. I got the same error. I have create a demo on github, if it is convenient for you, please download it and run it, when it starts downloading, you click home button, then open the app again, you will see the error. https://github.com/tuchangwei/data_task_convert_to_download_task – Changwei May 08 '16 at 02:27
0

The problem is evident from your own answer. It's not a bug, you simply couldn't use data tasks for background transfers just download tasks.

Here is the correct full answer.

BootMaker
  • 1,639
  • 1
  • 22
  • 24
  • Thanks, read the data from the tmp file is a good way to judge if I download is a media file or json data. – Changwei Oct 17 '17 at 02:41