以前在項目中遇到了加載高清大圖的場景,處理很差佔用大量內存,形成性能問題,影響用戶體驗。ios
如何去解決加載高清大圖這個難點呢?先看看iOS中的圖片加載流程。git
國外有文章對圖片的工做流寫的很清楚,這裏是連接。github
簡單來講是三步:bash
性能問題的通常是發生在解碼圖片這個步驟上,SDWebImage是提早強解碼圖片,這樣在渲染時就不會再發生解碼,其強解碼的代碼是在SDWebImageCoderHelper
中的decodedImageWithImage
函數中CGImageRef imageRef = [self CGImageCreateDecoded:image.CGImage];
。app
先說結論:不能。ide
測試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這種縮略圖的方案卻能很好適應這種場景。