如何使用URLSessionDownload下载图像?

时间:2017-11-18 19:15:09

标签: swift url download nsurlsession

我需要从服务器下载图像并在我的应用程序中显示它。我选择使用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!)
}

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

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文件夹中(因为URL中的文件location用于临时文件,一旦返回就会被删除):

/// 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。如果您要这样做,您必须做其他事情。例如,如果应用程序在后台请求完成时未运行,则app delegate必须捕获完成处理程序:

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(_:)