🐻优化GIF的内存加载

一、内存OOM问题

使用 UIImage.animatedImage(with:duration:) 方法:UIImage 类提供了一个便利的方法来加载并处理 GIF 图像,该方法可以将 GIF 图像转换为 UIImage 的动画表示。这种方法可以有效地管理内存,并且不需要手动处理每一帧的图像。但会存在内存问题,UIImage(contentsOfFile:) 虽然不会立即放入内存中,但显示时还是会加载到内存中。

ini 复制代码
if let gifURL = Bundle.main.url(forResource: "example", withExtension: "gif") {
    let gifData = try? Data(contentsOf: gifURL)
    let gifImage = UIImage.animatedImage(with: gifData)
    imageView.image = gifImage
}

大量的GIF会导致OOM问题,一旦使用超过系统的阈值,就会崩溃。

二、使用FLAnimatedImageView可以有效的解决GIF内存暴涨的问题

  • FLAnimatedImageView 使用渐进式解码:FLAnimatedImageView 使用渐进式解码来加载 GIF 图片。渐进式解码允许在图片尚未完全加载时就开始显示并逐步增加清晰度。这意味着 FLAnimatedImageView 可以在加载 GIF 图片的同时,逐帧渲染和显示动画,而不需要等待整个 GIF 图片加载完成。这对于大型 GIF 图片特别有利,因为可以显著降低首次加载的延迟,并提高用户体验。
  • 内存优化:FLAnimatedImageView 在加载和显示大型 GIF 图片时进行了内存优化。它只会将当前帧所需的数据加载到内存中,并在显示下一帧时释放之前的帧数据,从而避免占用过多的内存。这有助于在加载大型 GIF 图片时降低内存使用,减少内存压力和 OOM 问题。

三、让FLAnimatedImageView支持网络GIF

FLAnimatedImageView 是用于显示 GIF 动画的 FLAnimatedImage 库中的特殊控件,它并不直接用于加载网络图片,但我们可以扩展方法为其增加加载网络图片的功能。

swift 复制代码
import FLAnimatedImage
import Kingfisher

extension FLAnimatedImageView {
    func setGifImage(withURL url: URL) {
        // 使用 Kingfisher 加载网络图片
        self.kf.setImage(with: url, completionHandler: { result in
            switch result {
            case .success(let value):
                // 成功加载图片,value.image 是 UIImage 类型
                // 将加载的图片转换为 FLAnimatedImage 类型
                let animatedImage = FLAnimatedImage(animatedGIFData: value.image.kf.gifRepresentation())
                // 在 FLAnimatedImageView 中显示 GIF 动画
                self.animatedImage = animatedImage
            case .failure(let error):
                // 加载图片失败,处理错误
                print("Error loading image: (error)")
            }
        })
    }
}

上述方法利用Kingfisher不仅添加了缓存,还能后直接显示来自网络的GIF图片。

四、测试效果

总体内存可以降低70%,CPU在迅速滑动时波动较大,大概为原来的1-2倍,但是停止滑动时降低为原来的50%左右。由于目前iPhone手机的CPU普遍较好,而内存较低;所以这种用CPU缓解内存压力的方法是可行的。

相关推荐
蝎子莱莱爱打怪7 小时前
DSpark 讲透:DeepSeek 不换模型,硬把 V4 提速 85%,是怎么做到的?
人工智能·面试·程序员
程序员七平19 小时前
面试官:你说你Vibe Coding手拿把掐,那 Claude Code 用户级、项目级、本地级配置怎么隔离?
面试
葫芦和十三20 小时前
图解 MongoDB 17|大集合与工作集:数据超过内存怎么办
后端·mongodb·面试
葫芦和十三1 天前
图解 MongoDB 18|复制集拓扑:Primary、Secondary 和 Arbiter 的分工
后端·mongodb·面试
葫芦和十三1 天前
图解 MongoDB 15|journal 与持久化:写入怎么不丢,崩溃怎么恢复
后端·mongodb·面试
葫芦和十三1 天前
图解 MongoDB 16|压缩:snappy、zstd 和 zlib 的取舍
后端·mongodb·面试
labixiong2 天前
实现一个能跑的迷你版Promise(一)
前端·javascript·面试
weedsfly2 天前
还在用 Axios?你可能需要重新理解 XHR 与 Fetch
前端·javascript·面试
Hyyy2 天前
什么是bun?和pnpm有什么区别
前端·面试·bun
葫芦和十三2 天前
图解 MongoDB 14|Cache 与淘汰:WiredTiger 的内存治理
后端·mongodb·面试