Get the data from NSURLSession DownloadTaskWithRequest from completion handler

Jackky White picture Jackky White · Apr 6, 2015 · Viewed 8.8k times · Source

So I'm having hard time understanding something. This are the things I understand about NSURSession :

  • Generally , I have 2 options for (as far as I know) DataTask(e.x dataTaskWithRequest) And DownloadTask(e.x DownloadTaskWithRequest) - Using their delegate method , or use the completion handler , Can't do both. I have managed to receive DATA using dataTaskWithRequest like this :

    let request = NSMutableURLRequest(URL: dataSourceURL!)
    request.HTTPMethod = "POST"
    
    let postString = "lastid=\(id)"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in
    
        if error != nil {
            println("error=\(error)")
            return
        }
        if data != nil {
            println("works")
            //Handle data
    
    
        }
        //println("response = \(response)")
    
    
    }
    task.resume()      
    

It works perfectly. The problem is that I need to DOWNLOAD the data to the disk and not only to the memory(I'm downloading images). So I tried the same with DownloadTaskWithRequest + his completion handler and I have noticed that the parameters he takes are the same expect the first one which is NSURL and in DataTaskWithRequest is NSData so it makes things very simpler. ex.

 let task2 = NSURLSession.sharedSession().downloadTaskWithRequest(request, completionHandler: { (location : NSURL!, response : NSURLResponse!, error : NSError?) -> Void in
            if error != nil {
                return
            }

            //How do I get the data??
        })
task2.resume()

My Question is this : I know I can fetch the DATA out of the Location(NSURL) using :

    var data = NSData(contentsOfURL: location)

1)Will contentsOfURL will make another "request" do get this data , or that he is working locally? If it sending request again , how can I avoid it?

2)Is this the right way(I know I can use the delegate methods, I prefer not)?

3)How can I store the data i have downloaded(after questions number 1 and 2 answered) locally , and access it if needed?

Thank you guys!! Sorry for newbie question , I really do care about efficient - Thank you!

Answer

Rob picture Rob · Apr 6, 2015

When using download tasks, generally one would simply use the location provided by the completionHandler of the download task to simply move the file from its temporary location to a final location of your choosing (e.g. to the Documents or Cache folder) using NSFileManager.

let task = NSURLSession.sharedSession().downloadTaskWithURL(url) { location, response, error in
    guard location != nil && error == nil else {
        print(error)
        return
    }

    let fileManager = NSFileManager.defaultManager()
    let documents = try! fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
    let fileURL = documents.URLByAppendingPathComponent("test.jpg")
    do {
        try fileManager.moveItemAtURL(location!, toURL: fileURL)
    } catch {
        print(error)
    }
}
task.resume()

You certainly could also load the object into a NSData using contentsOfURL. Yes, it works with local resources. And, no, it won't make another request ... if you look at the URL it is a file URL in your local file system. But you lose much of the memory savings of download tasks that way, so you might use a data task if you really wanted to get it into a NSData. But if you wanted to move it to persistent storage, the above pattern probably makes sense, avoiding using a NSData object altogether.