🐻优化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缓解内存压力的方法是可行的。

相关推荐
元闰子1 小时前
怎么用CXL加速数据库?· SIGMOD'25
数据库·后端·面试
幂简集成1 小时前
GraphQL API 性能优化实战:在线编程作业平台指南
后端·性能优化·graphql
小高0072 小时前
🔥🔥🔥Vue部署踩坑全记录:publicPath和base到底啥区别?99%的前端都搞错过!
前端·vue.js·面试
蛋仔聊测试2 小时前
pytest源码解析(二)剖析 pytest 的核心组件
python·面试
Lingxing2 小时前
事件流:深入理解事件冒泡、事件捕获与事件委托
前端·javascript·面试
前端小白19952 小时前
面试取经:浏览器篇-跨标签页通信
前端·面试·浏览器
San302 小时前
JavaScript 入门精要:从变量到对象,构建稳固基础
javascript·面试·html
小猪乔治爱打球2 小时前
[Golang 修仙之路] 场景题:红包系统设计
后端·面试
小扳3 小时前
SpringBootWeb 篇-深入了解 ThreadLocal 存在内存泄漏问题
java·开发语言·spring boot·面试