首次加载时 NSCache 不适用于所有图像
NSCache Doesn't work with all images when loading for the first time
我正在 swift 3.0 中的一个项目中工作,我通过使用 NSCache 来缓存来自服务器的响应,以便将它们填充到 UITableView 中。但是由于某种原因,当应用程序第一次加载时,我只看到很少的图像加载,但是如果我滚动并返回,我会看到所有内容(从服务器检索响应结束我也重新加载我的 tableview,但似乎并非如此)。我不确定我在这里到底遗漏了什么,下面的代码显示了我如何缓存图像。
let imageCache = NSCache<AnyObject, AnyObject>()
var imageURLString : String?
extension UIImageView {
public func imageFromServerURL(urlString: String) {
imageURLString = urlString
if let url = URL(string: urlString) {
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil{
print(error as Any)
return
}
DispatchQueue.main.async(execute: {
if let imgaeToCache = UIImage(data: data!){
if imageURLString == urlString {
self.image = imgaeToCache
}
imageCache.setObject(imgaeToCache, forKey: urlString as AnyObject)// calls when scrolling
}
})
}) .resume()
}
}
}
我认为使用子类而不是扩展是更好的方法,(从 Jageen 的评论中得到帮助,因为我们不能在扩展中包含存储的属性,所以我们使用封装的想法)
let imageCache = NSCache<AnyObject, AnyObject>()
class CustomImageView: UIImageView {
var imageUrlString: String?
func loadImageUsingUrlString(_ urlString: String) {
let url = URL(string: urlString)
imageUrlString = urlString
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
let imageToCache = UIImage(data: data!)
if self.imageUrlString == urlString {
self.image = imageToCache
}
imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
}
}.resume()
}
}
-现在使用这个子类作为您在屏幕上显示的图像视图类型
此处图片正在下载并存储在缓存中。问题在于 table 视图单元格的更新。
当 table 视图将单元格加载到 table 时,图像尚未下载。但是一旦下载了图像,我们必须有选择地更新单元格,以便立即显示图像。
由于您正在滚动,table视图会再次调用 'cellForRowatIndexpath',这会在滚动时更新显示已下载图像的单元格。
如果您仍然希望使用该扩展程序,我建议您添加 table视图和索引路径作为参数,以便我们可以调用重新加载特定行并立即更新视图。
我更新了 table 扩展中定义的函数的重新加载代码和结构。让我知道进展如何。
let imageCache = NSCache<AnyObject, AnyObject>()
var imageURLString : String?
extension UIImageView {
public func imageFromServerURL(urlString: String, tableView : UITableView, indexpath : IndexPath)) {
imageURLString = urlString
if let url = URL(string: urlString) {
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil{
print(error as Any)
return
}
DispatchQueue.main.async(execute: {
if let imgaeToCache = UIImage(data: data!){
if imageURLString == urlString {
self.image = imgaeToCache
}
imageCache.setObject(imgaeToCache, forKey: urlString as AnyObject)// calls when scrolling
tableView.reloadRows(at: [indexpath], with: .automatic)
}
})
}) .resume()
}
}
我正在 swift 3.0 中的一个项目中工作,我通过使用 NSCache 来缓存来自服务器的响应,以便将它们填充到 UITableView 中。但是由于某种原因,当应用程序第一次加载时,我只看到很少的图像加载,但是如果我滚动并返回,我会看到所有内容(从服务器检索响应结束我也重新加载我的 tableview,但似乎并非如此)。我不确定我在这里到底遗漏了什么,下面的代码显示了我如何缓存图像。
let imageCache = NSCache<AnyObject, AnyObject>()
var imageURLString : String?
extension UIImageView {
public func imageFromServerURL(urlString: String) {
imageURLString = urlString
if let url = URL(string: urlString) {
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil{
print(error as Any)
return
}
DispatchQueue.main.async(execute: {
if let imgaeToCache = UIImage(data: data!){
if imageURLString == urlString {
self.image = imgaeToCache
}
imageCache.setObject(imgaeToCache, forKey: urlString as AnyObject)// calls when scrolling
}
})
}) .resume()
}
}
}
我认为使用子类而不是扩展是更好的方法,(从 Jageen 的评论中得到帮助,因为我们不能在扩展中包含存储的属性,所以我们使用封装的想法)
let imageCache = NSCache<AnyObject, AnyObject>()
class CustomImageView: UIImageView {
var imageUrlString: String?
func loadImageUsingUrlString(_ urlString: String) {
let url = URL(string: urlString)
imageUrlString = urlString
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
let imageToCache = UIImage(data: data!)
if self.imageUrlString == urlString {
self.image = imageToCache
}
imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
}
}.resume()
}
}
-现在使用这个子类作为您在屏幕上显示的图像视图类型
此处图片正在下载并存储在缓存中。问题在于 table 视图单元格的更新。
当 table 视图将单元格加载到 table 时,图像尚未下载。但是一旦下载了图像,我们必须有选择地更新单元格,以便立即显示图像。
由于您正在滚动,table视图会再次调用 'cellForRowatIndexpath',这会在滚动时更新显示已下载图像的单元格。
如果您仍然希望使用该扩展程序,我建议您添加 table视图和索引路径作为参数,以便我们可以调用重新加载特定行并立即更新视图。
我更新了 table 扩展中定义的函数的重新加载代码和结构。让我知道进展如何。
let imageCache = NSCache<AnyObject, AnyObject>()
var imageURLString : String?
extension UIImageView {
public func imageFromServerURL(urlString: String, tableView : UITableView, indexpath : IndexPath)) {
imageURLString = urlString
if let url = URL(string: urlString) {
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil{
print(error as Any)
return
}
DispatchQueue.main.async(execute: {
if let imgaeToCache = UIImage(data: data!){
if imageURLString == urlString {
self.image = imgaeToCache
}
imageCache.setObject(imgaeToCache, forKey: urlString as AnyObject)// calls when scrolling
tableView.reloadRows(at: [indexpath], with: .automatic)
}
})
}) .resume()
}
}