You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView快速滚动时indexPathsForVisibleRows判断失效问题求助

解决方案

核心问题分析

你现在的实现绕了没必要的弯路:手动检查缓存、用SDWebImagePrefetcher预加载,还要自己判断cell可见性,这些逻辑SDWebImage本身已经封装得非常完善。快速滚动时判断失效,本质是闭包捕获的indexPath和当前tableView的可见状态不同步,而且手动调用reloadRows的操作完全多余。

最优方案:直接使用SDWebImage的UIImageView扩展方法

SDWebImage的sd_setImage(with:placeholderImage:)方法内置了缓存检查、复用处理、自动更新UI的全部逻辑,完全不需要你手动写缓存判断和可见性检查,代码更简洁还能彻底解决问题。

修改后的代码如下:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell) as? TableViewCell else {
        // fallback code
    }
    
    let imageUrl = userData.imagePath
    // 替换成你的占位图资源名
    let placeholder = UIImage(named: "your_placeholder_image")
    
    if let url = URL(string: imageUrl) {
        // 直接用SDWebImage的扩展方法设置图片
        cell.yourImageView.sd_setImage(with: url, placeholderImage: placeholder) { [weak cell] _, _, cacheType, _ in
            // 仅当图片从网络加载完成时,触发cell布局调整(如果你的cell需要根据图片尺寸变化)
            if cacheType == .none {
                cell?.setNeedsLayout()
            }
        }
    } else {
        // URL无效时显示占位图
        cell.yourImageView.image = placeholder
    }
    
    return cell
}

为什么这个方案能解决问题:

  • 自动处理cell复用:当cell被滚动出屏幕并复用给其他indexPath时,SDWebImage会自动取消之前的加载请求,避免旧图片错误显示在新cell上。
  • 内置完整缓存逻辑:优先查询内存缓存,再查磁盘缓存,都没有才发起网络请求,完全不需要你手动调用SDImageCache做判断。
  • 无需手动刷新UI:图片加载完成后直接更新imageView的内容,cell会自动刷新显示,不需要调用reloadRows,自然也不存在可见性判断失效的问题。

如果你一定要保留预加载逻辑

如果因为业务需求必须用SDWebImagePrefetcher,可以把可见性判断改成更可靠的方式:直接查询当前tableView中对应indexPath的cell是否存在(存在则说明当前可见),并且直接更新cell的imageView,而不是调用reloadRows:

// 替换你原来的prefetch完成回调
SDWebImagePrefetcher.shared.prefetchURLs([url], progress: nil) { [weak self] _, _ in
    guard let self = self else { return }
    // 实时查询对应indexPath的cell,存在则说明当前可见
    if let cell = self.tableView.cellForRow(at: indexPath) as? TableViewCell {
        // 从缓存中取出图片设置给cell
        if let image = SDImageCache.shared.imageFromDiskCache(forKey: imageUrl) {
            cell.yourImageView.image = image
            cell.setNeedsLayout()
        }
    }
}

这个方式比检查indexPathsForVisibleRows更准确,因为cellForRow(at:)是实时查询当前tableView的可见cell,不会因为快速滚动导致数组状态不同步。

内容的提问来源于stack exchange,提问作者Madhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:02:48