【问题标题】:How to download an image using URLSessionDownload?如何使用 URLSession Download 下载图像?
【发布时间】:2017-11-18 19:15:09
【问题描述】:

我需要从服务器下载图像并将其显示在我的应用程序中。我选择使用URLSessionDownload 协议来获取下载状态和整个过程的进度。这是我的代码:

var downloadBGTask: URLSessionDownloadTask!
var downloadBGSession: URLSession!

override func viewDidLoad() {
    super.viewDidLoad()

    self.downloadBGSession = {
        let downloadBGSessionConfig = URLSessionConfiguration.background(withIdentifier: "downloadBGSession")
        return URLSession(configuration: downloadBGSessionConfig, delegate: self, delegateQueue: OperationQueue.main)
    }()

    self.downloadBGTask = self.downloadBGSession.downloadTask(with: "http.. ETC .png")
    self.downloadBGTask.resume()
}

协议

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64){
    self.loadingLabel.text = "Loading (\((Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)) * 100)%)"
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    print("Download Completed")

    // How do I get the image I downloaded?
    // This code below doesn't even compile
    self.randomImg.image = UIImage(data: downloadTask.response!)
}

有什么建议吗?

【问题讨论】:

    标签: swift url download nsurlsession


    【解决方案1】:

    location 是数据的临时文件 URL。所以你可以这样做:

    extension ViewController: URLSessionDownloadDelegate {
        ...
    
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
            print("Download Completed")
    
            let data = try! Data(contentsOf: location)
            randomImg.image = UIImage(data: data)
        }
    }
    

    或者,您也可以在使用前将其保存到 caches 文件夹中(因为 location 中的文件 URL 是一个临时文件,您一返回就会被删除):

    /// Local file URL for cached image
    
    let cachedImageFileURL = try! FileManager.default
        .url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("saved.png")
    

    然后:

    extension ViewController: URLSessionDownloadDelegate {
        ...
    
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
            print("Download Completed")
    
            imageDownloadInProgress = false
    
            try! FileManager.default.copyItem(at: location, to: cachedImageFileURL)
            let data = try! Data(contentsOf: location)
    
            randomImg.image = UIImage(data: data)
        }
    
    }
    

    但问题是你为什么要做背景URLSession。如果你要这样做,你必须做其他事情。例如,您的应用委托必须捕获完成处理程序,以防后台请求完成时应用未运行:

    var backgroundRequestCompletionHandler: (() -> Void)?
    
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        backgroundRequestCompletionHandler = completionHandler
    }
    

    然后你的视图控制器(如果它真的是URLSessionDelegate),必须在后台会话请求的处理完成时调用这个保存的完成处理程序:

    extension ViewController: URLSessionDelegate {
        func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
    
            appDelegate.backgroundRequestCompletionHandler?()
        }
    }
    

    但如果您这样做,viewDidLoad 总是启动新的下载是没有意义的(因为下载可能已经由应用程序的先前调用启动)。因此,在您发起下载请求之前,您可能希望它:

    • 从先前的请求中寻找缓存文件的存在;和
    • 检查是否正在下载(已将此状态保存在持久存储中或使用URLSession异步方法getTasksWithCompletionHandler(_:)

    【讨论】:

    • 你完全正确!我在做一些毫无意义的事情!我的第一个目标是尝试在动画开始之前下载并显示图像。但是如果连接不好(可能超时)我不知道如何处理
    • @user3582537 - 引入后台会话只会让它变得更加复杂。 dataTaskdownloadTask 的完成块再现要容易得多,恕我直言。在这些方法中,您只需检查DataURL 是否非nil 以及Error 引用是否为nil。但希望我已经向您展示了如何使用传回给您的URL 来执行下载任务。
    • 谢谢!我选择这种方式是因为当我使用 dataTask 完成时,它称为“完成”块,但在显示下载的图像之前大约需要 2/3 秒。但也许我应该为此发布另一个问题。感谢您的帮助和耐心
    • @user3582537 - 您是否将该 UI 更新分派到主队列? DispatchQueue.main.async { ... }。如果您尝试从后台队列执行这些 UI 更新而不将其分派回主队列,则会出现奇怪的延迟。
    猜你喜欢
    • 2021-12-01
    • 2017-09-28
    • 1970-01-01
    • 2019-02-05
    • 2017-04-13
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多