TableView图像直到滚动才加载

我正在使用Firebase将我的图片加载到我的单元格的ImageView ! 有一个问题。 我正在使用caching机制来防止可重复reusable cells格加载时重新下载图像,但图像不加载,直到我滚动我的TableView

这是代码;

  public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell cell.imgv.image = nil if let urlString = self.filteredFlats[indexPath.row].flatThumbnailImage?.imageDownloadURL { imageURLString = urlString let url = URL(string: urlString) if let imagefromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage { DispatchQueue.main.async { cell.imgv.image = imagefromCache return } } else { URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in DispatchQueue.main.async { let imagetoCache = UIImage(data:data!) if self.imageURLString == urlString { cell.imgv.image = imagetoCache } self.imageCache.setObject(imagetoCache!, forKey: urlString as AnyObject) } }).resume() } } return cell } 

我认为问题是,当URLSession下载图像并将其设置到ImageView ,但是直到上下滚动时调用indexpath.row才会显示加载的图像。

我意识到,这是如果陈述的原因;

  if self.imageURLString == urlString 

但是,如果我删除它,细胞越来越糟糕的可重用细胞的行为。 某些单元格仍显示旧的caching图像。

真的不知道发生了什么事情。 不期待TableViews是一种复杂的结构。

谢谢。

我猜测imageURLString是你的类的一个领域(UIViewController也许)。 这意味着imageURLString = urlString将在每次进入方法时更改其值。

当表格呈现时,它会调用每个单元格的方法,每次触发下载时,如果所需的图像不在caching中。 但在这些调用之后, imageURLString的值将是最后一个单元格的url,所以只有这个单元格才会使用已经加载的图片。

如果你想修正你的代码,你应该有一个imageURLString每个单元格,例如通过将字段移动到单元格类(在这种情况下创build一个UITableViewCell子类),并通过cell.imageURLStringreplaceimageURLStringcell.imageURLString

我相信imageCache必须是全局的,不应该放在tableView(_:cellForRowAt :)里面。

相反,除了var imageCache = String:UIImage之外,将所有东西都放在自定义UIImageView类中。 离开这个全球。

将所有将使用此CustomImageView类中的loadImage(urlString:String)函数的UIImageView更改为CustomImageView !.

例:

@IBOutlet弱var userImage:UIImageView!

改成

@IBOutlet弱var userImage:CustomImageView!

 import UIKit // global var var imageCache = [String: UIImage]() class CustomImageView: UIImageView { var lastURLUsedToLoadImage: String? func loadImage(urlString: String) { lastURLUsedToLoadImage = urlString self.image = nil if let cachedImage = imageCache[urlString] { self.image = cachedImage return } guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { (data, response, err) in if let err = err { print("Failed to fetch post image:", err) return } if url.absoluteString != self.lastURLUsedToLoadImage { return } guard let imageData = data else { return } let photoImage = UIImage(data: imageData) imageCache[url.absoluteString] = photoImage // update the UI DispatchQueue.main.async { self.image = photoImage } }.resume() } } 

调用加载方法的示例:

 cell.userImage.loadImage(urlString: userImageUrl) 

我使用以下从YouTube上的iOS教程中学习的方法来解决这个问题。 我们可以创build一个CustomImageView类, let imageCache = NSCache<AnyObject, AnyObject>()来保存图像caching。当滚动tableview时,如果imageView有一个imageCache,我们直接使用它。但是如果没有exsit,我们将下载带有图片URLstring的图片并保存。

 import UIKit let imageCache = NSCache<AnyObject, AnyObject>() class CustomImageView: UIImageView { var imageUrlString :String? func loadImageWithString(_ urlString:String){ imageUrlString = urlString let request = URLRequest(url: URL(string:urlString)!) self.image = nil //imageCache exist,and use it directly if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage { self.image = imageFromCache } //imageCache doesn't exist,then download the image and save it URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in guard let data = data, error == nil else { print(error?.localizedDescription as Any) return } DispatchQueue.main.async() { let imageToCache = UIImage(data: data) imageCache.setObject(imageToCache!, forKey: urlString as String as AnyObject ) if self.imageUrlString == urlString{ self.image = imageToCache } } }).resume() } } 

而在自定义的单元格文件中,我们可以使用它如下:

  if let imageUrlString = thumbnailUrlString { thumbnailImageView.loadImageWithString(imageUrlString) } 

注意1,thumbnailImageView:CustomImageView 2,thumbnailUrlString是可选的