长列表加载大图优化

在 iOS 使用 Kingfisher 加载大图时,如果没有优化,容易出现 内存暴涨、滚动卡顿 等问题。下面是针对 Kingfisher大图加载内存优化方案,帮助你减少内存占用,提升性能。

关键问题分析

Kingfisher 可能导致高内存占用的原因:

  1. 直接加载大图UIImage(data:) 可能会占用大量 RAM。
  2. 不合理的缓存策略(大图会存入内存,容易导致 OOM)。
  3. 未降采样(解码大图时,未按屏幕尺寸缩放)。
  4. UIImageView 处理过多的 GPU 渲染(影响滚动流畅度)。

解决方案

使用 Downsampling 降低内存占用

Kingfisher 提供 DownsamplingImageProcessor,可以降低大图的 RAM 使用

复制代码
import Kingfisher

let processor = DownsamplingImageProcessor(size: CGSize(width: 200, height: 200)) // 目标尺寸

imageView.kf.setImage(
    with: URL(string: "https://example.com/large-image.jpg"),
    options: [
        .processor(processor),  // 降采样,避免直接解码大图
        .scaleFactor(UIScreen.main.scale),  // 按屏幕缩放
        .cacheOriginalImage,  // 缓存原始图片,避免重复下载
        .transition(.fade(0.2))  // 平滑过渡
    ]
)
复制代码

调整 Kingfisher 缓存策略

Kingfisher 采用 内存缓存 + 磁盘缓存,默认情况下,大图可能会占用大量 RAM。可以手动优化缓存策略。

ImageCache.default.memoryStorage.config.totalCostLimit = 50 * 1024 * 1024  // 限制内存最大 50MB
ImageCache.default.memoryStorage.config.countLimit = 50  // 限制缓存 50 张图片

viewDidAppeardidReceiveMemoryWarning 时手动清理缓存

ImageCache.default.clearMemoryCache()  // 清理内存缓存
ImageCache.default.clearDiskCache()  // 清理磁盘缓存

使用 Placeholder 避免图片错位

UITableViewUICollectionView 由于复用机制,如果不使用占位图,可能会出现图片错乱

imageView.kf.setImage(
    with: URL(string: "https://example.com/large-image.jpg"),
    placeholder: UIImage(named: "placeholder")  // 占位图
)

同时在cell即将重用时设置imageview.image = nil

异步预加载图片

UITableView / UICollectionView 中滚动时,可以提前预加载即将显示的图片,提升加载速度。

let urls = [
    URL(string: "https://example.com/image1.jpg"),
    URL(string: "https://example.com/image2.jpg")
]

let prefetcher = ImagePrefetcher(urls: urls)
prefetcher.start()

减少 GPU 负担

如果 UIImageView 处理了过多的 GPU 渲染(如阴影、圆角等),可能会影响滚动流畅度。

cell.imageView?.layer.shouldRasterize = true
cell.imageView?.layer.rasterizationScale = UIScreen.main.scale

 

使用 Image I/O 降采样(更高效)

如果你需要进一步优化大图加载,可以使用 Image I/O 进行降采样(比 Kingfisher 更灵活)。

 

复制代码
import UIKit
import ImageIO

func downsample(imageAt imageUrl: URL, to pointSize: CGSize, scale: CGFloat = UIScreen.main.scale) -> UIImage? {
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    guard let imageSource = CGImageSourceCreateWithURL(imageUrl as CFURL, imageSourceOptions) else { return nil }

    let maxDimension = max(pointSize.width, pointSize.height) * scale
    let downsampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,
                             kCGImageSourceThumbnailMaxPixelSize: maxDimension,
                             kCGImageSourceShouldCacheImmediately: true] as CFDictionary

    guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else { return nil }

    return UIImage(cgImage: downsampledImage)
}
复制代码

 

posted @   程石亮  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示