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

UIImage导致UITableView渲染卡顿 如何优化性能提升滚动流畅度?

问题根因

当前代码存在三个核心性能问题直接导致滚动卡顿:

  • 同步在主线程执行网络请求:NSData(contentsOf: url)是同步方法,会直接卡住主线程等待网络返回,滚动时频繁调用必然产生严重掉帧
  • 主线程实时执行图片重绘缩放:图片缩放是CPU密集型操作,每次cell复用的时候都在主线程做重绘,占用大量主线程计算资源
  • 无任何缓存逻辑:同一张图片滚动出可视区域再滚回来,会重复执行下载、缩放逻辑,产生大量无效性能开销
    另外手动缩放图片适配UIImageView的操作完全是多余的,系统本身提供了contentMode属性可以自动完成图片适配,不需要手动重绘生成新图。
优化方案
  • 所有耗时操作异步执行:网络请求、图片缩放逻辑全部移到后台子线程执行,处理完成后再切回主线程赋值给UIImageView
  • 增加双层缓存:内存缓存存储已经处理好的适配后图片,同URL图片直接读取内存缓存即可使用;磁盘缓存存储原始下载的图片数据,无内存缓存时不需要重新发起网络请求
  • 提前预计算cell高度:请求到帖子数据时就提取图片的宽高比,在tableView(_:heightForRowAt:)方法中直接根据屏宽计算好图片高度和cell总高度返回,从根源解决cell高度错乱问题,不需要依赖图片加载完成后再调整布局
  • 替换网络请求方式:废弃NSData(contentsOf: url)同步网络请求,改用URLSession异步任务实现网络请求,避免主线程阻塞
  • 移除手动图片重绘逻辑:UIImageView的contentMode设置为.scaleAspectFill,加上约束固定图片的宽度、顶部/底部间距,系统会自动适配图片展示,不需要手动生成缩放后的图片

优化后核心逻辑示例

// 建议写在PostTableViewCell内部,cell复用的时候自动处理旧请求的校验
func set(post: Post) {
    self.post = post
    // 先重置图片,避免复用显示旧图
    self.MediaPhoto.image = nil
    // 先查内存缓存有没有处理好的图片
    if let cachedImage = ImageCache.shared.memoryCache.object(forKey: post.mediaURL as NSString) {
        self.MediaPhoto.image = cachedImage
        return
    }
    // 后台线程发起异步请求
    DispatchQueue.global().async {
        guard let url = URL(string: post.mediaURL),
              let imageData = try? Data(contentsOf: url),
              let originalImage = UIImage(data: imageData) else {
            return
        }
        // 后台线程处理图片缩放
        let targetWidth = UIScreen.main.bounds.width - 32 // 提前算好你的图片目标宽度
        let scale = targetWidth / originalImage.size.width
        let targetHeight = originalImage.size.height * scale
        let renderFormat = UIGraphicsImageRendererFormat()
        renderFormat.scale = UIScreen.main.scale
        let resizedImage = UIGraphicsImageRenderer(size: CGSize(width: targetWidth, height: targetHeight), format: renderFormat).image { context in
            originalImage.draw(in: CGRect(origin: .zero, size: CGSize(width: targetWidth, height: targetHeight)))
        }
        // 存缓存
        ImageCache.shared.memoryCache.setObject(resizedImage, forKey: post.mediaURL as NSString)
        // 切回主线程赋值
        DispatchQueue.main.async {
            // 校验当前cell对应的post是不是还是原来的,避免复用错乱
            guard self.post?.mediaURL == post.mediaURL else { return }
            self.MediaPhoto.image = resizedImage
        }
    }
}

// 简单的内存缓存实现示例
class ImageCache {
    static let shared = ImageCache()
    let memoryCache: NSCache<NSString, UIImage> = {
        let cache = NSCache<NSString, UIImage>()
        cache.countLimit = 100 // 最多缓存100张图,可根据需求调整
        return cache
    }()
    private init() {}
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 05:54:03