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!
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 Application Support directory, or Documents folder, or Cache folder, or whatever) using FileManager
.
let task = URLSession.shared.downloadTask(with: url) { location, response, error in
guard let location, error == nil else {
print(error ?? URLError(.unknown))
return
}
do {
let fileManager = FileManager.default
let fileURL = try fileManager
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appending(path: "test.jpg")
try fileManager.moveItem(at: location, to: fileURL)
} catch {
print(error)
}
}
task.resume()
Or from Swift concurrency (i.e., async
-await
):
let (location, _) = try await URLSession.shared.download(from: url)
let fileManager = FileManager.default
let fileURL = try fileManager
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appending(path: "test.jpg")
try fileManager.moveItem(at: location, to: fileURL)
You certainly could also load the object into a Data
using contentsOf
. 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 Data
. But if you wanted to move it to persistent storage, the above pattern probably makes sense, avoiding using a Data
object altogether.