導語:App中顯示的圖片大部分來自服務器,一般使用SDWebImage幫我們下載並顯示,但是這並不是最好的效果,本文介紹如何優化網絡圖片的顯示。
一、概述
1、SDWebImage庫概述
在SDWebImage庫中,SDWebImageManager是管理器,持有SDWebImageDownloader和SDImageCache單例,負責調度圖片的異步下載、緩存和獲取。
SDWebImageDownloader是下載器,負責異步圖片下載任務的調度,下載器中維持了一個圖片下載隊列,隊列中管理若干SDWebImageDownloaderOperation下載任務;該任務繼承自NSOperation,封裝了圖片的下載任務,支持並發操作。圖片下載的網絡請求和響應是由NSURLSession類負責管理的。SDImageCache是緩存器,負責下載圖片的緩存和讀取。
總之,SDWebImage庫提供了一整套的網絡圖片異步下載和緩存機制,還增加了UIImageView、UIButton等的Category,方便顯示網絡圖片。
2、存在的問題
由於網絡圖片一般不會有@2x和@3x之分,通過SDWebImage庫下載的圖片不加以處理就直接顯示,會有一些常見的問題,如像素不對齊。
App中經常使用圓角圖片,一般采用裁剪圖片的方式;但是這些圖片源來自服務器(本地圓角圖片讓UI直接提供就可以了),我們需要在SDWebImage基礎上增加對網絡圓角圖片的處理。
二、常見圖片顯示問題
主要有三類:像素不對齊、像素混合 和圓角處理
1、像素不對齊
像素不對齊是指物理像素(pixel)不對齊;出現像素不對齊,會導致GPU在渲染時,對沒對齊的邊緣,進行插值計算,造成性能損耗了。
當圖片的size和顯示圖片View的size不同 或 圖片的scale和屏幕的scale不同,就會發生像素不對齊的問題。要想像素對齊,必須保證image.size和顯示圖片view.size相等 且 image.scale和 [UIScreen mainScreen].scale相等。
iPhone模擬器中的Debug -> Color Misaligned Images選項 或Core Animation->Display Settings->Color Misaligned Images選項都可以將像素不對齊的部分顯示出來。
當UIView(及其子類)的frame像素不對齊顯示洋紅色;當圖片的像素大小與控件的大小不一致,顯示黃色。
說明:了解更多請參考iOS優化錄1:解決iOS中像素不對齊問題
2、像素混合
像素混合是指在某視圖為透明背景色,GPU在渲染視圖時,需要將該視圖和下層視圖混合(Blend)後才能計算出該像素點的實際顏色;這增加了GPU的工作,損耗了性能。
當圖片是透明圖片時,像素混合必然會發生。所以顯示的圖片最好是不透明的。
iPhone模擬器中的Debug ->Color Blended Layers選項 和 Core Animation ->Display Settings ->Color Blended Layers都可以將像素混合的部分顯示出來。
發生了像素混合的區域顯示紅色,正常則顯示綠色。
說明:之前對像素混合的關注比較少,而像素混合對性能的影響有多大,還需要後續工作中去驗證;但是可以避免像素混合就盡量避免。
3、圓角圖片的問題
不建議的方案1:通過設置cornerRadius值和masksToBounds=YES實現圓角效果。因為它會觸發GPU的離屏渲染,引起性能問題。模擬器中的Color Offscreen-Rendered可以檢測是否發生離屏渲染(如果出現黃色就發生了離屏渲染)。
不建議的方案2:通過設置view.layer的mask屬性,將另一個layer蓋在view上,也可以實現圓角的效果,但是同樣會觸發離屏渲染,引起性能問題。
可參考的方案:在需要添加圓角的視圖上再疊加一個部分透明的視圖,只對圓角部分進行遮擋。雖然不會有離屏渲染和額外的GPU計算,但是不靈活,使用范圍有限。
建議的方案:使用Core Graphics重新繪制帶圓角的圖片,雖然在顯示上提升了性能,但是增加了繪制的工作,所以要做好異步繪制和緩存工作,盡可能避免重復繪制。
說明:離屏渲染是圖片圓角處理中討論比較多的問題,利用Core Graphics繪制是個比較主流的選擇。
三、QSImageProcess方案
QSImageProcess方案是我定制的圖片處理方案,為了適應對本地圖片以及網絡圖片的處理,做了一些優化工作。
1、核心類:QSImageProcess
可以同步或異步處理圖片,接口定義如下:
typedef void(^QSImageProcessCompletedBlock)(UIImage *outputImage); @class QSImageProcessConfig; @interface QSImageProcess : NSObject /** 圖片處理配置對象 */ @property (nonatomic,strong)QSImageProcessConfig *config; + (nonnull instancetype)sharedInstance; /** 異步圖片處理 @param image 待處理的圖片 @param config 圖片處理配置對象 @param completedBlock 處理完成塊 */ - (void)processImage:(UIImage *)image config:(QSImageProcessConfig *)config completed:(QSImageProcessCompletedBlock)completedBlock; /** 同步圖片處理 @param image 待處理的圖片 @param config 圖片處理配置對象 @return 返回處理好的圖片 */ - (UIImage *)processImage:(UIImage *)image config:(QSImageProcessConfig *)config; @end
說明:圖片的處理是耗時操作,在異步處理中,將該任務應交給GCD並發隊列,通過QSDispatchQueue控制並發隊列的最大並發數
2、UIImageView的QSImageProcess分類
@interface UIImageView (QSImageProcess) /** 加載並顯示網絡圖片,調用前需要先設置好UIImageView的frame或bounds @param url 圖片url @param placeholder 圖片處理配置對象 */ - (void)qs_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder; /** 加載並顯示網絡圖片 @param url 圖片url @param placeholder 占位圖 @param config 圖片處理配置對象 */ - (void)qs_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder config:(QSImageProcessConfig *)config; @end
說明1:接口1不需要設置QSImageProcessConfig對象,采用默認的方式,根據UIImageView的size來輸出顯示不發生 像素混合和像素不對齊的圖片。
說明2:接口2使用時候,通過配置QSImageProcessConfig對象,然後交由SDWebImageExtension去異步裁剪、縮放圖片,最後顯示出來。
3、其他
QSProcessImageConfig是圖片處理配置對象,可以設置option(圖片處理選項)、outputSize(圖片輸出大小)、clipBgColor(裁剪圖片需要的背景顏色)、cornerRadius(圓角半徑)、corners(需要處理的圓角)等。
圖片的處理包括裁剪圓角、添加蒙版等(後期繼續補充)。
typedef NS_ENUM(NSInteger,QSImageProcessOption) { QSImageProcessOptionDefault = 0, QSImageProcessOptionClipCorner = 1, QSImageProcessOptionCircle = 2, QSImageProcessOptionRound = 3, QSImageProcessOptionAddGradationMask = 4, QSImageProcessOptionAddWholeMask = 5 };
圖片處理使用Core Graphics實現。在使用UIGraphicsBeginImageContextWithOptions創建上下文時候,opaque默認為YES,表示不透明;如果是裁剪,需要傳入背景色,否則被裁去的部分是黑色。
四、QSImageProcess方案的使用
1、使用介紹
a) 安裝QSImageProcess
pod 'QSImageProcess'
b) 引入頭文件
#import "QSImageProcess.h" #import "UIImageView+QSImageProcess.h"
c) 代碼示范
//加載網絡圖片1,默認config [self.imageView qs_setImageWithURL:url placeholderImage:placeholderImage]; //加載網絡圖片2,自定義config QSImageProcessConfig *config = [QSImageProcessConfig configWithOutputSize:self.imageView.frame.size cornerRadius:cornerRadius corners:UIRectCornerAllCorners]; [self.imageView qs_setImageWithURL:url placeholderImage:placeholderImage config:configs]; //處理本地圖片 QSImageProcessConfig *config = [QSImageProcessConfig configWithOutputSize:self.imageView.frame.size cornerRadius:cornerRadius corners:UIRectCornerAllCorners]; //異步 [[QSImageProcess sharedInstance]processImage:image config:config completed:^(UIImage *outputImage) { self.imageView1.image = outputImage; }]; //同步 self.imageView2.image = [[QSImageProcess sharedInstance]processImage:image config:config];
2、效果1
簡單實現一個Demo,通過QSImageProcess實現對本地圖片的不同處理。
說明1:模擬器開啟了Color Blended Layers、Color Misaligned Images選項。
說明2:沒有開啟Color Offscreen-Rendered是因為Controller通過push進入,整個Controller在下是顯示黃色(離屏渲染),這和系統的UINavigationController有關,具體原因需要後續去發現。使用present彈出不會有這個問題。
說明3:第三行第三列(第9個)圖片出現被紅色區域覆蓋,說明這裡出現了像素混合,這是因為該圖片處理要求輸出透明的圓形圖片。其config對象如下:
QSImageProcessConfig *config9 = [QSImageProcessConfig circleConfigWithOutputSize:_cellSize]; //透明圓形圖片
3、效果2
簡單實現一個Demo,通過UIImageView (QSImageProcess)分類實現對網絡圖片的不同處理。
說明1:模擬器開啟了Color Blended Layers、Color Misaligned Images選項。
說明2:經過處理的網絡圖片,最後通過SDWebCache緩存下來,相同的繪制需求不需要重復繪制。
說明3:被紅色區域覆蓋的圖片,是因為該圖片處理要求輸出透明的圓形圖片(發生像素混合了)。
End
相關文章
iOS實錄5:iOS中本地圖片的縮放、裁剪和壓縮
項目地址
QSImageProcess