因为下载图片前只有url,所以无法预测下载到的图片的大小。如果不进行优化处理,加载到大图就会导致内存飙升,图片足够大或数量足够多时还会有 OOM 的风险。
所以终端必须对图片的加载进行优化处理。
如这张图:
-
文件大小:3.4M

1、直接加载
加载图片前 demo 项目内存占用为:25.5M
若下载后直接加载到内存,总内存大小为:84.2M,占用了 58.7M:

2、图片采样
对图片进行采样:
// 1. 创建 CGImageSource 对象
// kCGImageSourceShouldCache 是否需要解码缓存
let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL,
imageSourceOptions) else {
print("create image source error")
return
}
// 2. 计算采样像素
let maxDimensionInPixels = max(size.width, size.height) * scale
// 3. 配置采样参数
let sampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true, // 进行解码和缓存
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
// 4. 创建缩略图
guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, sampleOptions) else {
print("create thumbnail image error")
return
}
self.imageView.image = downsampledImage
加载到内存之后,总内存为 27.2M,占用了 2.2 M:

3、采样 vs 缩小图片
缩小处理代码如下:
let renderer = UIGraphicsImageRenderer(size: size)
let renderImage = renderer.image { context in
image.draw(in: CGRect(origin: .zero, size: size))
}
self.imageView.image = renderImage
但根据苹果工程师 Kyle Howarth 所说,由于内部坐标系的变换,这样做效果也不会如预想的那么好。内部坐标空间变换是昂贵的。
建议使用采样,ImageIO可以在不污染内存的情况下读取图像尺寸和元数据信息 ImageIO可以调整图像的大小,但只以调整后的图像为代价
下采样相比于缩小图片是更适合的优化方式。