UITableView 异步图像并不总是正确的

问题描述

我有一个 UITableView,在我的应用程序初始加载期间,它会发送多个 API 请求。当每个 API 请求返回时,我向 UITableView 添加一个新行。因此,初始加载在随机时间以随机顺序添加行(大多数情况下都在一秒钟内发生)。

在单元格设置期间,我调用 Async 方法生成 MKMapKit MKMapSnapshotter 图像。

我之前使用过异步图像加载没有问题,但我很少会在错误的单元格中看到图像,我不知道为什么。

我尝试切换到 DiffableDataSource,但问题仍然存在。

在我的 DiffableDataSource 中,我将一个闭包传递给在图像异步返回时调用的单元格,以在当前单元格发生更改时获取它:

let dataSource = DiffableDataSource(tableView: tableView) {
            (tableView,indexPath,journey) -> UITableViewCell? in
            
            let cell = tableView.dequeueReusableCell(withIdentifier: "busCell",for: indexPath) as! journeyTableViewCell
            cell.setupCell(for: journey) { [weak self] () -> (cell: journeyTableViewCell?,journey: journey?) in
                
                if let self = self
                {
                    let cell = tableView.cellForRow(at: indexPath) as? journeyTableViewCell
                    let journey = self.sortedjourneys()[safe: indexPath.section]
                    return (cell,journey)
                }
                return(nil,nil)
            }
            
            return cell
        }

这是我的手机设置代码

override func prepareForReuse() {
    super.prepareForReuse()
    
    setMapImage(nil)
    journey = nil
    asyncCellBlock = nil
}

func setupCell(for journey:journey,asyncUpdateOriginalCell:@escaping journeyOriginalCellBlock) {
    
    self.journey = journey
    
    // Store the async block for later
    asyncCellBlock = asyncUpdateOriginalCell
    
    // Map
    if let location = journey.location,(CLLocationCoordinate2disValid(location.coordinate2D))
    {
        // Use the temp cached image for Now while we get a new image
        if let cachedImage = journey.cachedMap.image
        {
            setMapImage(cachedImage)
        }
        
        // Request an updated map image
        journey.createMapImage {
            [weak self] (image) in
            
            dispatchQueue.main.async {
                
                if let asyncCellBlock = self?.asyncCellBlock
                {
                    let asyncResult = asyncCellBlock()
                    if let cell = asyncResult.cell,let journey = asyncResult.journey
                    {
                        if (cell == self && journey.id == self?.journey?.id)
                        {
                            self?.setMapImage(image)
                            
                            // Force the cell to redraw itself.
                            self?.setNeedsLayout()
                        }
                    }
                }
            }
        }
    }
    else
    {
        setMapImage(nil)
    }
}

我不确定这是否只是 UITableView 在短时间内更新多次的竞争条件。

解决方法

我认为这是因为当图像可用时,该索引不存在。由于表格视图单元格是可重用的,它会加载上一张图片,因为当前图片尚未加载。

if let cachedImage = journey.cachedMap.image
    {
        setMapImage(cachedImage)
    }
else {
        // make imageView.image = nil
}
,

我可以看到您已经缓存了图像,但我认为您应该像这样准备单元以供重复使用:

override func prepareForReuse() {
    super.prepareForReuse()
    let image = UIImage()
    self.yourImageView.image = image
    self.yourImageView.backgroundColor = .black
}