图片占用内存太大

2021-07-09  本文已影响0人  iLeooooo

最近发现项目中一个简单的列表,滚动的时候,内存增长特别快!!! 随便滚动几下就涨到1G

一、图片本身太大了,让后台改图片大小走不通,只能自己动手了

我使用的是Kingfisher加载图片:

let escapedString = picurl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
picImg.kf.setImage(with: URL(string: escapedString!), options: [.backgroundDecode, .fromMemoryCacheOrRefresh])

在方法里面有options有:processor 加工者,自定义data|image转成image的逻辑
Processor的用法

自定义一个Processor对图片进行处理:
public struct DealProcessor: ImageProcessor {
    public static let `default` = DealProcessor()
    public let identifier = "DealProcessor"
    public init() {}
    
    public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        switch item {
        case .image(let image):
            return image
        case .data(let data):
            let image = UIImage(data: data)
            if let imgData = image?.jpegData(compressionQuality: 0.1) {
                return UIImage(data: imgData)
            }
            return image
        }
    }
}

结果:跑起来发现,图片的质量降低了是降低了,图片的Data也相应的变小了,但是内存该涨还是涨,一番花里胡哨的操作并没有解决问题

二、图片占用的内存的原因

图片在内存中占用空间大小与文件大小无关,与其图像尺寸成正相关。一张尺寸为 2268 * 4032 的图片,其内存占用为:2268 * 4032 * 4 / 1024 / 1024 = 34.88M (这里假设每个像素占用的空间为 4 字节),而文件大小只有 3.7M
来源

到这里发现内存爆涨的原因不是图片本身太大,而是图片的尺寸太大了

所以解决方法就来了:对加载的图片进行加工,对图片的尺寸进行重设,然后在返回

加工方法:

public struct DealProcessor: ImageProcessor {
    public static let `default` = DealProcessor()
    public let identifier = "DealProcessor"
    public init() {}
    
    public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        switch item {
        case .image(let image):
            return image
        case .data(let data):
            let image = UIImage(data: data)
            if let im = image?.reSizeImage(reSize: CGSize(width: 110, height: 80)) {
                return im
            } else {
                return image
            }
        }
    }
}

extension UIImage {
     /**
      *  重设图片大小
      */
     func reSizeImage(reSize: CGSize )-> UIImage?  {
        
        UIGraphicsBeginImageContextWithOptions(reSize, false, UIScreen.main.scale)
        self.draw(in: CGRect(x: 0, y: 0, width: reSize.width, height: reSize.height))
        let resImg: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resImg
     }
}
加工方法的使用:
picImg.kf.setImage(with: URL(string: escapedString!), options: [.processor(DealProcessor.default)])

结果:内存没有暴涨!!!问题解决

结论:

  1. 图片在内存中占用空间大小与文件大小无关,与其图像尺寸成正相关。
  2. 使用Kingfisher加载图片的时候,对加载的图片进行加工的方法:使用options的.processor(DealProcessor.default)


Kingfisher的options的解释 引用来自

1. targetCache,originalCache
2. downloader
3. downloadPriority 下载优先级
4. transition
5. forceTransition
6. forceRefresh 是否强制刷新,若值为true,则不使用缓存
7. fromMemoryCacheOrRefresh 当值为true时,刷新的时候,若使用缓存,则只使用内存缓存,不去磁盘缓存
8. cacheMemoryOnly 是否只使用内存缓存
9. waitForCache 是否等待缓存完成,再调用回调
10. onlyFromCache 是否只从缓存中加载
11. backgroundDecode 是否在子线程去解码
12. preloadAllAnimationData
 @objc extension UIImageView {
    func shouldPreloadAllAnimation() -> Bool { return true }
 }

 public func setImage(
    with source: Source?,
    placeholder: Placeholder? = nil,
    options: KingfisherOptionsInfo? = nil ...
   -> DownloadTask? {
         ...
        //若shouldPreloadAllAnimation()的值为true
        //则把preloadAllAnimationData设为true
        //而ImageView中的shouldPreloadAllAnimation()一直为true
         if base.shouldPreloadAllAnimation() {
            options.preloadAllAnimationData = true
         }
        ...  
} 
13. onlyLoadFirstFrame 若图片是GIF图时,是否只显示第一帧
14. callbackQueue,processingQueue
15. requestModifier 发送请求时对原始的请求进行修改,返回新的Request
16. redirectHandler 当请求发生重定向是,自定义的一些处理
17. processor 加工者,自定义data|image转成image的逻辑
18. imageModifier image修饰器,对image做一些修改,比如返回 image.withRenderingMode(renderingMode)
19. cacheSerializer 定义图片序列化和反序列化
20. keepCurrentImageWhileLoading 当加载一个新图时,是否要保持当前的图片
21. cacheOriginalImage 是否要缓存原始的数据
22. onFailureImage 加载失败时,要展示的图片
23. alsoPrefetchToMemory 预加载时,需要从磁盘加载时,是否也需要同步到内存中
24. loadDiskFileSynchronously 从磁盘中加载时,是否同步的去加载
25. memoryCacheExpiration,diskCacheExpiration 设置内存、磁盘缓存过期时间
26. memoryCacheAccessExtendingExpiration
27. alternativeSources 当加载失败时,可供替代的数据源
28. onDataReceived 接收到数据时,需要回调时,可设置此属性,比如setImage时设置的DownloadProgressBlock,就是在里面封装了此属性
上一篇下一篇

猜你喜欢

热点阅读