UITableView Async图像不总是正确的



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

在单元设置期间,我调用Async方法来生成MKMapKitMKMapSnapshotter映像。

我以前没有使用过异步图像加载,但很少我最终在错误的单元格中的图像,我不知道为什么。

我已经尝试切换到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
}

最新更新