高清大图加载优化

4,757 阅读3分钟

高清大图加载的问题

之前在项目中遇到了加载高清大图的场景,处理不好占用大量内存,造成性能问题,影响用户体验。

如何去解决加载高清大图这个难点呢?先看看iOS中的图片加载流程。

iOS中图片的加载流程

国外有文章对图片的工作流写的很清楚,这里是链接

简单来说是三步:

  • 1、加载图片数据,这里的图片数据尚未解码
  • 2、解码图片数据
  • 3、渲染图片

性能问题的一般是发生在解码图片这个步骤上,SDWebImage是提前强解码图片,这样在渲染时就不会再发生解码,其强解码的代码是在SDWebImageCoderHelper中的decodedImageWithImage函数中CGImageRef imageRef = [self CGImageCreateDecoded:image.CGImage];

用SDWebImage能解决吗?

先说结论:不能。

测试SDWebImage的代码如下:

imageView.sd_setImage(with: url!) { (image, error, cacheType, theUrl) in
            print(image?.size)
        }

使用Instruments可以看出SDWebImage的内存占用非常大,加载测试图这样图片内存占用达到270MB,峰值内存达到800MB+。

可以看出,SDWebImage无法解决高清图内存占用过高和内存峰值过高的问题。

优化的思路

SDWebImage加载高清图的性能问题,主要是其直接加载高清图的原来尺寸导致的,而加载一张图片的内存占用 = 图片Width * 图片Height * 4。所以直接加载测试图的原始分辨率的内存占用是 7033 * 10100 * 4 / (1024 * 1024) = 约270MB

因此,对于高清图的加载,需要采用缩减分辨率的方法来减轻加载的内存压力,这里使用DownSampling的方法,具体的方法介绍看WWDC2018-最佳图像实践这个Session。

DownSampling的具体原理是,在图像解码之前加入创建缩略图的过程,对加载的Image进行预处理,减少解码后的Image Buffer的大小,从而减少加载的内存占用和内存峰值。

这是DownSampling的示例代码:

func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
    
    //生成CGImageSourceRef 时,不需要先解码。
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    
    //在创建Thumbnail时直接解码
    let downsampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,
                             kCGImageSourceShouldCacheImmediately: true,
                             kCGImageSourceCreateThumbnailWithTransform: true,
                             kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
    //生成UIImage,强制解码
    let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
    return UIImage(cgImage: downsampledImage)
}

这是使用DownSampling优化后的Instrument内存监测:

对比

加载方式 内存占用 内存峰值
SDWebImage 270MB 800MB+
DownSampling 14MB 40MB

从对比中可以看出,使用DownSampling能大大降低内存的占用和峰值。

总结

对于高清大图的场景来说,内存的占用尤为重要,如何降低图片占用的内存,对提升用户体验有着至关重要的作用。从上面的对比中可以看出,使用SDWebImage是难以应对高清大图这种场景的,而DownSampling这种缩略图的方案却能很好适应这种场景。

参考资料

Image and Graphics Best Practices 谈谈 iOS 中图片的解压缩