What is difference between URLSession vs DispatchQueue.global().async + Data(contentsOf: ) in terms of download images from image urls?
func loadImageWithUrlSession() {
guard let url = URL(string: IMAGE_URL) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let data = data else { return }
let image = UIImage(data: data)
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.urlSessionImageView.image = image
}
}.resume()
}
func loadImageWithGCD() {
DispatchQueue.global(qos: .background).async {
guard
let url = URL(string: self.IMAGE_URL),
let data = try? Data(contentsOf: url) else {
return
}
let image = UIImage(data: data)
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.gcdImageView.image = image
}
}
}
I know that URLSession can cancel or suspend task.
But if I use Rx instead, I can do the same thing as above as well.
I had an experiment that and it was depending on which QoS I'm using.
By the way, .userInitiated QoS was way faster than URLSession.
Which one are you guys use for something like downloading task with a background thread and why?
Is there any kind-teacher can help me specifically?
URLSession offers far greater configuration control, diagnostics of failures, cancelation, background sessions, ability to download directly to persistent storage to minimize peak memory usages, etc. URLSession and Data(contentsOf:) just are not comparable on feature set.
The synchronous Data(contentsOf:) unnecessarily blocks GCD worker threads and is also susceptible to misuse. It also is quite limiting and you will easily find yourself regretting the decision in the future (e.g. you later add some authentication process; you want to customize the cache behaviors, you want to parse and act upon status codes in the responses, you need cancelation capabilities because you are retrieving images for collection or table views, etc.).
It’s illuminating to look at the documentation for one of the init with a URL methods for Data, where it warns us:
Important
Don't use this synchronous initializer to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.
Instead, for non-file URLs, consider using the
dataTask(with:completionHandler:)method of theURLSessionclass. See Fetching Website Data into Memory for an example.
Yes, dispatching this to a background thread addresses many of the above concerns, but Apple didn’t just suggest “just dispatch this to some background queue,” but rather explicitly advised to use URLSession instead. While your use of GCD global queue avoids some of issues that Apple warns us of above, it also imposes many unnecessarily limitations. If you use Data(contentsOf:), this is a decision that you’ll likely regret/refactor in the future. You might as well use URLSession now.
Regarding Data(contentsOf:) being appreciably faster when using .userInitiated, vs .default or URLSession approach, usually the network latency and transmission time dwarfs any queue priority related factors, so I find that claim hard to believe. In fact, I just tested download of 50 images via GCD (using both .default and .userInitiated) and the speed was not appreciably different than URLSession approach.