我想增强下面的代码来缓存图像,只有在以前没有缓存它们时才下载它们.我似乎无法找到如何使用URLSession对象执行此操作的任何好例子.
extension UIImageView {
func loadImageWithURL(_ url: URL) -> URLSessionDownloadTask {
let session = URLSession.shared
let downloadTask = session.downloadTask(with: url, completionHandler: { [weak self] url, response, error in
if error == nil, let url = url,
let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
DispatchQueue.main.async {
if let strongSelf = self {
strongSelf.image = image
}
}
}
})
downloadTask.resume()
return downloadTask
}
}
Run Code Online (Sandbox Code Playgroud)
iAj*_*iAj 11
针对Swift 3进行了更新
import UIKit
let imageCache = NSCache<AnyObject, AnyObject>()
class ImageLoader: UIImageView {
var imageURL: URL?
let activityIndicator = UIActivityIndicatorView()
func loadImageWithUrl(_ url: URL) {
// setup activityIndicator...
activityIndicator.color = .darkGray
addSubview(activityIndicator)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
imageURL = url
image = nil
activityIndicator.startAnimating()
// retrieves image if already available in cache
if let imageFromCache = imageCache.object(forKey: url as AnyObject) as? UIImage {
self.image = imageFromCache
activityIndicator.stopAnimating()
return
}
// image does not available in cache.. so retrieving it from url...
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil {
print(error as Any)
DispatchQueue.main.async(execute: {
self.activityIndicator.stopAnimating()
})
return
}
DispatchQueue.main.async(execute: {
if let unwrappedData = data, let imageToCache = UIImage(data: unwrappedData) {
if self.imageURL == url {
self.image = imageToCache
}
imageCache.setObject(imageToCache, forKey: url as AnyObject)
}
self.activityIndicator.stopAnimating()
})
}).resume()
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
// assign ImageLoader class to your imageView class
let yourImageView: ImageLoader = {
let iv = ImageLoader()
iv.frame = CGRect(x: 10, y: 100, width: 300, height: 300)
iv.backgroundColor = UIColor(red: 0.94, green: 0.94, blue: 0.96, alpha: 1.0)
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
// unwrapped url safely...
if let strUrl = "https://picsum.photos/300/300".addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),
let imgUrl = URL(string: strUrl) {
yourImageView.loadImageWithUrl(imgUrl) // call this line for getting image to yourImageView
}
Run Code Online (Sandbox Code Playgroud)
小智 6
对此的一种潜在解决方案是利用NSCache
来处理缓存。本质上,您要做的是检查您是否已经在本地加载了图像,而不是在您实际发出请求之前每次都获取。
然而,这是我的一个实现 - 它是一个子类而不是扩展:
class CustomImageView: UIImageView {
// MARK: - Constants
let imageCache = NSCache<NSString, AnyObject>()
// MARK: - Properties
var imageURLString: String?
func downloadImageFrom(urlString: String, imageMode: UIViewContentMode) {
guard let url = URL(string: urlString) else { return }
downloadImageFrom(url: url, imageMode: imageMode)
}
func downloadImageFrom(url: URL, imageMode: UIViewContentMode) {
contentMode = imageMode
if let cachedImage = imageCache.object(forKey: url.absoluteString as NSString) as? UIImage {
self.image = cachedImage
} else {
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
let imageToCache = UIImage(data: data)
self.imageCache.setObject(imageToCache!, forKey: url.absoluteString as NSString)
self.image = imageToCache
}
}.resume()
}
}
}
Run Code Online (Sandbox Code Playgroud)
此外,这里有一个有用的资源:https : //www.hackingwithswift.com/example-code/system/how-to-cache-data-using-nscache