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

Swift 5如何在UICollectionView中加载7000张以上图片解决卡顿闪退问题

UICollectionView加载大量相册图片卡顿/闪退优化方案

现有代码核心问题

  • 一次性发起数千张图片的同步加载请求,阻塞运行线程
  • 将所有加载完成的UIImage全量存入内存数组,图片数量超过3000后内存占用远超iOS应用上限,直接触发闪退
  • 图片请求配置不合理,同步+高质量格式请求进一步加剧性能消耗

具体优化方案

1. 取消全量预加载,改为按需加载

  • 不要全量请求所有图片,数组仅存储PHAsset对象,单张PHAsset内存占用仅几字节,存7000条也只有几十KB,完全无压力
  • 仅在UICollectionView的cellForItemAt方法中,针对当前要显示的cell发起对应单张图片的请求

2. 优化PHImageRequestOptions配置

// 全局复用同一个请求配置即可,不要每次请求重复创建
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false // 关闭同步,避免阻塞线程
requestOptions.deliveryMode = .opportunistic // 先返回低清缩略图,再返回高清图,提升响应速度
requestOptions.resizeMode = .fast
requestOptions.isNetworkAccessAllowed = true

3. 使用PHCachingImageManager替代默认PHImageManager

系统自带的缓存管理类会自动管理图片缓存,还支持预加载功能:

// 全局初始化缓存管理器
let cachingImageManager = PHCachingImageManager()
// 当滚动停止时,预加载当前可见区域前后10个cell的图片,提升滑动流畅度
func prefetchImages(for indexPaths: [IndexPath]) {
    let assets = indexPaths.map { self.assets[$0.item] }
    cachingImageManager.startCachingImages(for: assets, targetSize: CGSize(width:150, height: 200), contentMode: .aspectFill, options: requestOptions)
}
// 滑动过快时,取消已经滑出屏幕的cell的图片请求,避免无效资源占用
func cancelPrefetching(for indexPaths: [IndexPath]) {
    let assets = indexPaths.map { self.assets[$0.item] }
    cachingImageManager.stopCachingImages(for: assets, targetSize: CGSize(width:150, height: 200), contentMode: .aspectFill, options: requestOptions)
}

4. 优化UICollectionView加载逻辑

  • 实现UICollectionViewDataSourcePrefetching协议,处理预加载和取消请求逻辑
  • 滑动过程中降低图片请求优先级,滚动停止后再提升优先级加载高清图
  • cell重用时清空旧的图片,取消之前绑定的请求,避免出现图片错位

5. 优化后核心代码

var assets: [PHAsset] = [] // 仅存PHAsset,不存UIImage
let cachingImageManager = PHCachingImageManager()
let requestOptions = PHImageRequestOptions()

func grabPhotos(){
    let options = PHFetchOptions()
    options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
    
    let assetsFetchResult = (collection == nil) ?  PHAsset.fetchAssets(with: .image, options: options) : PHAsset.fetchAssets(in: collection!, options: nil)
    // 直接存储PHAsset数组,不要全量请求图片
    assets = assetsFetchResult.objects(at: IndexSet(integersIn: 0..<assetsFetchResult.count))
    
    // 初始化请求配置
    requestOptions.isSynchronous = false
    requestOptions.deliveryMode = .opportunistic
    requestOptions.resizeMode = .fast
    requestOptions.isNetworkAccessAllowed = true
    
    DispatchQueue.main.async {
        self.categoryView.reloadData()
        self.activityIndicator.stopAnimating()
    }
}

// cellForItemAt中按需加载图片
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
    let asset = assets[indexPath.item]
    // 先清空旧图片,避免重用错位
    cell.imageView.image = nil
    // 请求当前cell需要的图片
    cachingImageManager.requestImage(for: asset, targetSize: CGSize(width:150, height: 200), contentMode: .aspectFill, options: requestOptions) { image, _ in
        DispatchQueue.main.async {
            cell.imageView.image = image
        }
    }
    return cell
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 05:39:04