gpt4 book ai didi

ios - 自定义 UICollectionViewCell 未从缓存中加载

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:03:53 28 4
gpt4 key购买 nike

我有一个自定义的 UICollectionViewCell 定义如下:

class MomentsCell: UICollectionViewCell {
@IBOutlet weak var imageView: UIImageView!}

我的委托(delegate)方法看起来是这样的:

    override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! MomentsCell
let imageURL = imageURLS[indexPath.row]
self.updateImageForCell(cell: cell,
inCollectionView: collectionView,
withImageURL: imageURL,
atIndexPath: indexPath)
return cell

“updateImageForCell”方法如下所示:

    func updateImageForCell(cell: MomentsCell,
inCollectionView collectionView: UICollectionView,
withImageURL: String,
atIndexPath indexPath: IndexPath) {
/*if let url = URL(string: withImageURL) {
cell.imageView.setImageWith(url, placeholderImage: UIImage(named: "placeholder"))
}*/
cell.imageView.image = UIImage(named: "placeholder")
ImageManager.shared.downloadImageFromURL(withImageURL) {
(success, image) -> Void in
if success && image != nil {
// checks that the view did not move before setting the image to the cell!
if collectionView.cellForItem(at: indexPath) == cell {
cell.imageView.image = image
}
}
}
}

ImageManager 是一个包含一定数量图像缓存的单例。如果图像 URL 在缓存中,则返回缓存的图像。如果没有,它会启动一个 URLSession 以从 Firebase 下载图像。

图像会在 View 首次加载时显示出来,这向我表明此时一切都或多或少地正常工作。然而,当我滚动时,随机图像被加载,有些最终没有被加载,最终所有的单元格都变成空白并且无论如何都不会加载,即使所有内容都保存在缓存中。

这很傻,但这是我的 ImageManager 类:

class ImageManager: NSObject {
static var shared: ImageManager { return _singletonInstance }
var imageCache = [String : UIImage]()

// checks the local variable for url string to see if the UIImage was already downloaded
func cachedImageForURL(_ url: String) -> UIImage? {
return imageCache[url]
}

// saves a downloaded UIImage with corresponding URL String
func cacheImage(_ image: UIImage, forURL url: String) {
// First check to see how many images are already saved in the cache
// If there are more images than the max, we have to clear old images
if imageCache.count > kMaxCacheImageSize {
imageCache.remove(at: imageCache.startIndex)
}
// Adds the new image to the END of the local image Cache array
imageCache[url] = image
}

func downloadImageFromURL(_ urlString: String,
completion: ((_ success: Bool,_ image: UIImage?) -> Void)?) {

// First, checks for cachedImage
if let cachedImage = cachedImageForURL(urlString) {
completion?(true, cachedImage)
} else {
guard let url = URL(string: urlString) else {
completion?(false,nil)
return
}
print("downloadImageFromURL")

let task = URLSession.shared.downloadTask(with: url,
completionHandler: { (url, response, error) in

print("downloadImageFromURL complete")


if error != nil {
print("Error \(error!.localizedDescription)")
} else {
if let url = URL(string: urlString),
let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
self.cacheImage(image, forURL: url.absoluteString)
DispatchQueue.main.async(execute: { completion?(true, image) })
}
}
}
})
task.resume()
}
}

func prefetchItem(url urlString: String) {
guard let url = URL(string: urlString) else {
return
}

let task = URLSession.shared.downloadTask(with: url,
completionHandler: { (url, response, error) in
if error != nil {
print("Error \(error!.localizedDescription)")
} else {
if let url = URL(string: urlString),
let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
self.cacheImage(image, forURL: url.absoluteString)
}
}
}
})
task.resume()
}

如有任何帮助,我们将不胜感激。如果我遗漏了任何重要信息,请告诉我。

最佳答案

这里有多个问题,但我相信只有第一个问题导致您的图像根本不显示。

  1. 在设置图像之前检查单元格是否相同时的行:collectionView.cellForItem(at: indexPath) == cellcellForItem 实际上返回 nil 因为它在屏幕外。它在下载图像时起作用,因为有时间将其显示在屏幕上,但是当从缓存中拉出图像时,您的 completionHandler 会立即被调用,因此单元格尚未返回到 collectionView!

    对此有多种解决方案,但也许最简单的是添加返回到您的 completionHandler 的 wasCached 标志(请参阅此答案末尾的代码)。

  2. 您实际上下载了每张图片两次:首先,使用 URLSession.shared.downloadTask,然后当您从下载任务的 url 获取数据时,再次在 completionHandler 中。您要传递给 的 URL 试试? Data(contentsOf: url) 是来自服务器的图像 URL,而不是 completionHandler 中返回的文件 URL。

  3. 来自 Apple's documentation of downloadTask(with:completionHandler:)传递到您正在阅读的 completionHandler block 的 URL:

    The location of a temporary file where the server’s response is stored. You must move this file or open it for reading before your completion handler returns. Otherwise, the file is deleted, and the data is lost.

如果您不需要磁盘缓存,那么要修复#2 和#3,请改用 dataTask(with:completionHandler:) 函数,它会为您提供内存中已有的图像数据,并且你可以从中构建图像。

func downloadImageFromURL(
_ urlString: String,
completion: ((_ success: Bool,_ image: UIImage?, _ wasCached: Bool) -> Void)?) {

// First, checks for cachedImage
if let cachedImage = cachedImageForURL(urlString) {
print("Found cached image for URL \(urlString)")
completion?(true, cachedImage, true)
} else {
guard let url = URL(string: urlString) else {
completion?(false,nil, false)
return
}
print("downloadImageFromURL \(urlString)")

let task = URLSession.shared.dataTask(with: url) { data, response, error in
print("downloadImageFromURL complete \(urlString)")
if let error = error {
print("Error \(urlString) \(error.localizedDescription)")
} else if let data = data, let image = UIImage(data: data) {
self.cacheImage(image, forURL: url.absoluteString)
DispatchQueue.main.async { completion?(true, image, false) }
}
}
task.resume()
}
}

及其用法:

ImageManager.shared.downloadImageFromURL(withImageURL) { success, image, wasCached in
if success && image != nil {
// checks that the view did not move before setting the image to the cell!
if wasCached || collectionView.cellForItem(at: indexPath) == cell {
cell.imageView.image = image
}
}
}

关于ios - 自定义 UICollectionViewCell 未从缓存中加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49437813/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com