【问题标题】:swift: load the image data in backgroundswift:在后台加载图像数据
【发布时间】:2023-04-06 19:44:01
【问题描述】:

我需要在单元格中加载 100 张图片。如果我在 tableView cellForRowAt 中使用此方法:

cell.cardImageView.image = UIImage(named: "\(indexPath.row + 1).jpg")

并开始快速滚动我的tableView 冻结。

我使用这种方法在后台加载修复冻结的图像数据:

func loadImageAsync(imageName: String, completion: @escaping (UIImage) -> ()) {
    DispatchQueue.global(qos: .userInteractive).async {
        guard let image = UIImage(named: imageName) else {return}
        DispatchQueue.main.async {
            completion(image)
        }
    }
}

在tableView cellForRowAt 中调用这个:

loadImageAsync(imageName: "\(indexPath.row + 1).jpg") { (image) in
        cell.cardImageView.image = image
}

但我在这种方法中可能会出现一个错误,即在快速滚动时,我可能会在一段时间内看到旧图像。如何修复此错误?

【问题讨论】:

  • @matt 为什么我的问题不投票?也许我应该添加更多信息?
  • 老图显示一段时间是合理的,除非新图加载,旧图显示。在我看来,您可以使用占位符来显示,以防尚未加载新图像。
  • @matt 你能举个例子吗?因为我在网上搜索这个但没有任何帮助。

标签: ios swift uitableview


【解决方案1】:

您的单元格正在被重复使用。

当单元格离开屏幕时,它会进入内部 UITableViews 重用池,当您在 tableView(_:cellForRowAt:) 中的 dequeueReusableCell(withIdentifier:for:) 时,您会再次获得此单元格(参见名称中的“可重用”)。了解UITableViewCell 的生命周期很重要。 UITableView 不能在 100 行中保存 100 个生活 UITableViewCells,这会降低性能并很快让应用程序没有内存。

为什么您会在自己的单元格中看到旧图像? 同样,单元格正在被重用,重用后它们保持旧状态,您需要重置图像,它们不会自行重置。您可以在配置新单元时执行此操作,或者检测单元何时将被重用。

就这么简单:

cell.cardImageView.image = nil // reset image
loadImageAsync(imageName: "\(indexPath.row + 1).jpg") { (image) in
        cell.cardImageView.image = image
}

另一种方法是检测重用和重置。在您的单元格子类中:

override func prepareForReuse() {
    super.prepareForReuse()
    self.cardImageView.image = nil // reset
}

为什么在单元格中看到错误的图像? 当completion 闭包将图像设置为cardImageView 时,UITableViewCell 已被重复使用(甚至可能不止一次)。为了防止这种情况,您可以测试是否在同一单元格中设置图像,例如,将图像名称与您的单元格一起存储,然后:

// naive approach

let imageName = "\(indexPath.row + 1).jpg"
cell.imageName = imageName
loadImageAsync(imageName: imageName) { (image) in
    guard cell.imageName == imageName else { return } 
    cell.cardImageView.image = image
}

在设计列表时需要注意很多事情,我不会在这里详细介绍。我建议尝试上述方法并调查网络如何处理列表的性能问题。

【讨论】:

    【解决方案2】:

    在你的单元格类中你需要声明

    override func prepareForReuse() {
        super.prepareForReuse()
    }
    

    为重复使用准备单元格

    【讨论】:

    • 我需要声明prepareForReuse ?并使用cell.cardImageView.image = UIImage(named: "\(indexPath.row + 1).jpg")?没有别的吗?
    • 如果我添加 prepareForReuse() 没有任何变化
    猜你喜欢
    • 2017-01-03
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    相关资源
    最近更新 更多