【问题标题】:Wrong Images loading in some of tableView.dequeueReusableCell在某些 tableView.dequeueReusableCell 中加载错误的图像
【发布时间】:2022-02-12 07:14:56
【问题描述】:

我的tableView 有以下代码:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
        
        // Reset the image in the cell
        cell.coverImageView.image = nil
        
        // Get the recipe that the tableView is asking about
        let recipeInTable = recipe[indexPath.row]
        
        cell.displayRecipe(recipe: recipeInTable, indexPathRow: indexPath.row)

        return cell
    }

这是我的自定义单元类,我正在缓存要从中提取的图像数据:

class CustomCell: UITableViewCell {
    
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var coverImageView: UIImageView!
    
    var recipeToDisplay:Recipe?
    var recipeToPullFrom:Recipe!
    
    func displayRecipe(recipe:Recipe, indexPathRow:Int) {
        
        recipeToPullFrom = recipe
        
        DispatchQueue.main.async {
            self.titleLabel.text = self.recipeToPullFrom.title
            
            if self.recipeToPullFrom.image == nil {
                return
            }
            else {
                let urlString = self.recipeToPullFrom.image

                if let imageData = CacheManager.retrieveData(urlString!) {
                    
                    self.coverImageView.image = UIImage(data: imageData)
                    return
                }
                
                let url = URL(string: urlString!)
                
                guard url != nil else {
                    print("Could not create url object")
                    return
                }
                
                let session = URLSession.shared
                
                let dataTask = session.dataTask(with: url!) { (data, response, error) in

                    if error == nil && data != nil  {

                        CacheManager.saveData(urlString!, data!)

                        if self.recipeToPullFrom.image == urlString {
                            DispatchQueue.main.async {
                                // Display the image data in the imageView
                                self.coverImageView.image = UIImage(data: data!)
                            }
                        }
                        DispatchQueue.main.async {
                            self.coverImageView.image = UIImage(data: data!)
                        }
                    } // End if

                } // End dataTask

                // Kick off the dataTask
                dataTask.resume()
            }
        }
    }
}

最后是我的缓存管理器:

class CacheManager {
    
    static var imageDictionary = [String:Data]()
    
    static func saveData(_ url:String, _ imageData:Data) {
        // Save the image data along with the url
        imageDictionary[url] = imageData
    }
    
    static func retrieveData(_ url:String) -> Data? {
        // Return the saved imageData or nil
        return imageDictionary[url]
    }
}

根据我的研究,在我的tableView 函数中添加以下内容应该会在输入新图像之前重置我的单元格中的图像:cell.coverImageView.image = nil

我有什么遗漏吗?我还注意到只有我的图像显示在错误的单元格中。从缓存中检索图像数据时我是否做错了什么?

非常感谢任何方向或支持!

【问题讨论】:

  • 有两次self.coverImageView.image = UIImage(data: data!),为什么?您正在检查一个 URL,而不是另一个。此外,由于应该在主线程中调用 cellForRow,因此不需要 displayRecipe 顶层的 Dispatch.main.sync

标签: ios swift uitableview caching tableview


【解决方案1】:

由于您的图像是异步下载的,因此可以在将单元格重新用于另一个对象后下载它。你可以做什么:

  • 当您的图像准备好显示(下载)时,您需要检查它是否应该显示在该单元格中。

或者

  • 您还可以保留对URLSessionDataTask 的引用并在重用单元格之前取消它,方法是覆盖prepareForReuse 方法。

【讨论】:

    【解决方案2】:

    我认为您不需要在这里进行异步调用,尤其是当您在其他.main 中使用.main 时。 But If you what so you what so make some things like

    DispatchQueue.global(qos: .userInteractive).async {
        // Never do here ui code - label, view, images.. anything; or would crash
        DispatchQueue.main.async {
            // To do here you ui updates
        }
    }
    

    这里是一些使用重用方法的重构代码。我同意 哈希3m。如果下一个单元格即将显示,你需要取消请求,如果你不再这样做了

    class CustomCell: UITableViewCell {
            @IBOutlet private weak var titleLabel: UILabel!
            @IBOutlet private weak var coverImageView: UIImageView!
    
            private var dataTask: URLSessionDataTask?
    
            func displayRecipe(recipe: Recipe, indexPathRow: Int) {
                titleLabel.text = recipe.title enter code here
                guard let urlString = recipe.image else { return }
    
                if let imageData = CacheManager.retrieveData(urlString) {
                    coverImageView.image = UIImage(data: imageData)
                    return
                }
    
                guard let url = URL(string: urlString) else { return print("Could not create url object") }
    
                dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
                    guard let data = data else { return self.clear() }
                    CacheManager.saveData(urlString, data)
                    self.coverImageView.image = UIImage(data: data)
                }
    
                dataTask?.resume()
            }
    
            override func prepareForReuse() {
                super.prepareForReuse()
                clear()
            }
    
            private func clear() {
                dataTask?.cancel()
                dataTask = nil
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      • 1970-01-01
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多