如何使用 URLSession 下载图片?
How to download an image using URLSessionDownload?
我需要从服务器下载图像并将其显示在我的应用程序中。我选择使用 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!)
}
有什么建议吗?
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)
}
}
或者,您也可以在使用前将其保存到缓存文件夹中(因为 location
中的文件 URL
是一个临时文件,一旦您 return):
/// 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(_:)
。
我需要从服务器下载图像并将其显示在我的应用程序中。我选择使用 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!)
}
有什么建议吗?
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)
}
}
或者,您也可以在使用前将其保存到缓存文件夹中(因为 location
中的文件 URL
是一个临时文件,一旦您 return):
/// 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(_:)
。