从图像 url 下载图像方面,URLSession 与 GCD 有啥区别?

Posted

技术标签:

【中文标题】从图像 url 下载图像方面,URLSession 与 GCD 有啥区别?【英文标题】:What is difference between URLSession vs GCD in terms of download image from image url?从图像 url 下载图像方面,URLSession 与 GCD 有什么区别? 【发布时间】:2019-03-25 07:17:54 【问题描述】:

URLSession vs DispatchQueue.global().async + Data(contentsOf: ) 从图片 url 下载图片有什么区别?

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
        
    

我知道URLSession 可以取消或暂停任务。 但是如果我改用 Rx,我也可以做和上面一样的事情。

我做了一个实验,这取决于我使用的 QoS。 顺便说一句,.userInitiated QoS 比 URLSession 快得多。 你们将哪一个用于诸如通过后台线程下载任务之类的事情,为什么?

有没有哪位好心的老师可以具体帮帮我?

【问题讨论】:

使用 UrlSession 代替 Data(contentsOf: url)。第一个是异步的,第二个是同步的。不要使用此同步初始化程序来请求基于网络的 URL。对于基于网络的 URL,这种方法会在慢速网络上阻塞当前线程数十秒,导致用户体验不佳,并且在 ios 中可能会导致您的应用被终止。相反,对于非文件 URL,请考虑使用 URLSession 类的 dataTask(with:completionHandler:) 方法。 还可以查看以下链接:developer.apple.com/documentation/foundation/nsdata/… 【参考方案1】:

URLSession 提供了更强大的配置控制、故障诊断、取消、后台会话、直接下载到持久存储以最小化峰值内存使用的能力等。URLSessionData(contentsOf:) 在功能集上没有可比性.

同步的Data(contentsOf:) 会不必要地阻塞 GCD 工作线程并且也容易被误用。这也是相当有限的,你很容易发现自己在将来后悔这个决定(例如,你稍后添加一些身份验证过程;你想自定义缓存行为,你想解析响应中的状态码并采取行动,你需要取消功能,因为您正在检索图像以用于集合或表格视图等)。

使用Data 的 URL 方法查看 the documentation 中的一个 init 是很有启发性的,它会警告我们:

重要

不要使用此同步初始化程序来请求基于网络的 URL。对于基于网络的 URL,此方法会在慢速网络上阻塞当前线程数十秒,导致用户体验不佳,并且在 iOS 中可能会导致您的应用被终止。

对于非文件 URL,请考虑使用 URLSession 类的 dataTask(with:completionHandler:) 方法。示例见Fetching Website Data into Memory。

是的,将其分派到后台线程解决了上述许多问题,但 Apple 不仅建议“将其分派到某个后台队列”,而是明确建议改用 URLSession。虽然您使用 GCD 全局队列避免了 Apple 在上面警告我们的一些问题,但它也施加了许多不必要的限制。如果您使用Data(contentsOf:),这是您将来可能会后悔/重构的决定。您不妨现在使用URLSession


关于Data(contentsOf:) 在使用.userInitiated 时明显更快,与.defaultURLSession 方法相比,通常网络延迟和传输时间使任何与队列优先级相关的因素相形见绌,所以我觉得这种说法很难相信。事实上,我刚刚测试了通过 GCD 下载 50 张图片(同时使用 .default.userInitiated),速度与 URLSession 方法没有明显不同。

【讨论】:

以上是关于从图像 url 下载图像方面,URLSession 与 GCD 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Swift URLSession 通过 REST api 将图像和其他参数作为表单数据发布?

从 URL 下载 UITableIViewCell 图像

如何从 URL 下载图像

从 URL 下载图像并添加到滚动视图子视图

如何使用从适配器传递的 url 下载图像

强制从 URL 下载图像的最长时间