侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

优化UITableView中图片加载导致的卡顿问题

2025-12-11 / 0 评论 / 4 阅读

题目

优化UITableView中图片加载导致的卡顿问题

信息

  • 类型:问答
  • 难度:⭐

考点

异步加载, 图片缓存, 单元格复用

快速回答

解决UITableView图片加载卡顿的核心方法:

  • 使用异步加载避免阻塞主线程
  • 实现内存缓存和磁盘缓存减少重复下载
  • 正确处理单元格复用时的图片请求
  • 对图片进行尺寸压缩和解码优化
## 解析

问题原因

当在UITableViewCell中直接同步加载或下载大尺寸图片时,会导致:

  • 主线程被阻塞造成滚动卡顿
  • 重复下载相同图片浪费资源
  • 未处理的单元格复用引发图片错乱

解决方案与代码示例

1. 异步加载(核心)

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    let imageUrl = dataArray[indexPath.row].imageUrl

    // 先设置占位图
    cell.imageView?.image = UIImage(named: "placeholder")

    // 异步加载
    DispatchQueue.global().async {
        guard let url = URL(string: imageUrl),
              let data = try? Data(contentsOf: url),
              let image = UIImage(data: data) else { return }

        // 主线程更新UI
        DispatchQueue.main.async {
            // 验证单元格是否仍可见
            if let updateCell = tableView.cellForRow(at: indexPath) {
                updateCell.imageView?.image = image
                updateCell.setNeedsLayout()
            }
        }
    }
    return cell
}

2. 图片缓存(NSCache示例)

class ImageCache {
    static let shared = NSCache<NSString, UIImage>()
}

// 使用缓存
if let cachedImage = ImageCache.shared.object(forKey: imageUrl as NSString) {
    cell.imageView?.image = cachedImage
} else {
    // 异步下载并缓存
    downloadImageAndCache(url: imageUrl, for: indexPath)
}

3. 单元格复用处理

// 在cellForRowAt开始时取消旧请求
cell.tag = indexPath.row

// 在异步回调中检查
DispatchQueue.main.async {
    if cell.tag == indexPath.row { // 验证单元格未复用
        cell.imageView?.image = image
    }
}

最佳实践

  • 使用第三方库:SDWebImage或Kingfisher自动处理异步/缓存/复用
  • 图片压缩:请求服务端返回合适尺寸的图片
  • 解码优化:在后台线程进行UIGraphicsImageRenderer绘制
  • 预加载:在cellWillDisplay时提前加载下一页数据

常见错误

  • 在主线程同步下载图片(致命错误)
  • 未处理单元格复用导致图片错乱
  • 缓存无限增长引发内存警告
  • 加载原始大图(应使用缩略图)

扩展知识

  • 磁盘缓存:使用URLCache或FileManager持久化存储
  • 渐进式加载:先显示模糊图再逐渐清晰
  • RunLoop优化:在DefaultMode加载图片,滚动时暂停任务
  • 矢量图替代:简单图标使用PDF/SFSymbol减少资源体积