长列表加载大图优化
在 iOS 使用 Kingfisher 加载大图时,如果没有优化,容易出现 内存暴涨、滚动卡顿 等问题。下面是针对 Kingfisher 的 大图加载内存优化方案,帮助你减少内存占用,提升性能。
关键问题分析
Kingfisher 可能导致高内存占用的原因:
- 直接加载大图(
UIImage(data:)
可能会占用大量 RAM。 - 不合理的缓存策略(大图会存入内存,容易导致 OOM)。
- 未降采样(解码大图时,未按屏幕尺寸缩放)。
- 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 张图片
在 viewDidAppear
或 didReceiveMemoryWarning
时手动清理缓存
ImageCache.default.clearMemoryCache() // 清理内存缓存 ImageCache.default.clearDiskCache() // 清理磁盘缓存
使用 Placeholder 避免图片错位
UITableView
和 UICollectionView
由于复用机制,如果不使用占位图,可能会出现图片错乱。
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) }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架