SDWebImage
一個為UIImageView提供一個分類來支持遠(yuǎn)程服務(wù)器圖片加載的庫膨蛮。
功能簡介:
1敞葛、一個添加了web圖片加載和緩存管理的UIImageView分類
2惹谐、一個異步圖片下載器
3、一個異步的內(nèi)存加磁盤綜合存儲圖片并且自動處理過期圖片
4综液、支持動態(tài)gif圖
5、支持webP格式的圖片
6檩奠、后臺圖片解壓處理
7埠戳、確保同樣的圖片url不會下載多次
8整胃、確保偽造的圖片url不會重復(fù)嘗試下載
9屁使、確保主線程不會阻塞
工作流程
1蛮寂、入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage 顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片及老。
2骄恶、進(jìn)入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 queryDiskCacheForKey:delegate:userInfo:.
3匕垫、先從內(nèi)存圖片緩存查找是否有圖片僧鲁,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
4悔捶、SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片铃慷。
5、如果內(nèi)存緩存中沒有蜕该,生成 NSInvocationOperation 添加到隊列開始從硬盤查找圖片是否已經(jīng)緩存。
6堂淡、根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件敛滋。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:蹋肮。
7胶滋、如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小皆的,會先清空內(nèi)存緩存)覆履。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:。進(jìn)而回調(diào)展示圖片费薄。
8硝全、如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片楞抡,需要下載圖片伟众,回調(diào) imageCache:didNotFindImageForKey:userInfo:。
9召廷、共享或重新生成一個下載器 SDWebImageDownloader 開始下載圖片凳厢。
10、圖片下載由 NSURLConnection 來做竞慢,實現(xiàn)相關(guān) delegate 來判斷圖片下載中先紫、下載完成和下載失敗。
11筹煮、connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進(jìn)度加載效果泡孩。connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
12寺谤、圖片解碼處理在一個 NSOperationQueue 完成仑鸥,不會拖慢主線程 UI。如果有需要對下載的圖片進(jìn)行二次處理变屁,最好也在這里完成眼俊,效率會好很多。
13粟关、在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成疮胖,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader。imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。
14澎灸、通知所有的 downloadDelegates 下載完成院塞,回調(diào)給需要的地方展示圖片。將圖片保存到 SDImageCache 中性昭,內(nèi)存緩存和硬盤緩存同時保存拦止。寫文件到硬盤也在以單獨 NSInvocationOperation 完成,避免拖慢主線程糜颠。
15汹族、SDImageCache 在初始化的時候會注冊一些消息通知,在內(nèi)存警告或退到后臺的時候清理內(nèi)存圖片緩存其兴,應(yīng)用結(jié)束的時候清理過期圖片顶瞒。
16、SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache元旬,方便使用榴徐。
17、SDWebImagePrefetcher 可以預(yù)先下載圖片匀归,方便后續(xù)使用箕速。
源碼分析
主要用到的對象
一、圖片下載
1朋譬、 SDWebImageDownloader
1.單例,圖片下載器兴垦,負(fù)責(zé)圖片異步下載徙赢,并對圖片加載做了優(yōu)化處理
2.圖片的下載操作放在一個NSOperationQueue并發(fā)操作隊列中,隊列默認(rèn)最大并發(fā)數(shù)是6
3.每個圖片對應(yīng)一些回調(diào)(下載進(jìn)度探越,完成回調(diào)等)狡赐,回調(diào)信息會存在downloader的URLCallbacks(一個字典,key是url地址钦幔,value是圖片下載回調(diào)數(shù)組)中枕屉,URLCallbacks可能被多個線程訪問,所以downloader把下載任務(wù)放在一個barrierQueue中鲤氢,并設(shè)置屏障保證同一時間只有一個線程訪問URLCallbacks搀擂。,在創(chuàng)建回調(diào)URLCallbacks的block中創(chuàng)建了一個NSOperation并添加到NSOperationQueue中卷玉。
4.每個圖片下載都是一個operation類哨颂,創(chuàng)建后添加到一個隊列中,SDWebimage定義了一個協(xié)議 SDWebImageOperation作為圖片下載操作的基礎(chǔ)協(xié)議相种,聲明了一個cancel方法威恼,用于取消操作。
@protocol SDWebImageOperation <NSObject>
-(void)cancel;
@end
- 5.對于圖片的下載,SDWebImageDownloaderOperation完全依賴于NSURLConnection類箫措,繼承和實現(xiàn)了NSURLConnectionDataDelegate協(xié)議的方法
connection:didReceiveResponse:
connection:didReceiveData:
connectionDidFinishLoading:
connection:didFailWithError:
connection:willCacheResponse:
connectionShouldUseCredentialStorage:
-connection:willSendRequestForAuthenticationChalleng
-connection:didReceiveData:方法腹备,接受數(shù)據(jù),創(chuàng)建一個CGImageSourceRef對象斤蔓,在首次獲取數(shù)據(jù)時(圖片width植酥,height),圖片下載完成之前附迷,使用CGImageSourceRef對象創(chuàng)建一個圖片對象惧互,經(jīng)過縮放、解壓操作生成一個UIImage對象供回調(diào)使用喇伯,同時還有下載進(jìn)度處理喊儡。
注:縮放:SDWebImageCompat中SDScaledImageForKey函數(shù)
解壓:SDWebImageDecoder文件中decodedImageWithImage
2、SDWebImageDownloaderOption
1.繼承自NSOperation類稻据,沒有簡單實現(xiàn)main方法艾猜,而是采用更加靈活的start方法,以便自己管理下載的狀態(tài)
2.start方法中創(chuàng)建了下載使用的NSURLConnections對象捻悯,開啟了圖片的下載匆赃,并拋出一個下載開始的通知,
3.小結(jié):下載的核心是利用NSURLSession加載數(shù)據(jù)今缚,每個圖片的下載都有一個operation操作來完成算柳,并將這些操作放到一個操作隊列中,這樣可以實現(xiàn)圖片的并發(fā)下載姓言。
3瞬项、SDWebImageDecoder(異步對圖片進(jìn)行解碼)
二、緩存
減少網(wǎng)絡(luò)流量何荚,下載完圖片后存儲到本地囱淋,下載再獲取同一張圖片時,直接從本地獲取餐塘,提升用戶體驗妥衣,能快速從本地獲取呈現(xiàn)給用戶。
SDWebImage提供了對圖片進(jìn)行了緩存戒傻,主要由SDImageCache完成税手。該類負(fù)責(zé)處理內(nèi)存緩存以及一個可選的磁盤緩存,其中磁盤緩存的寫操作是異步的需纳,不會對UI造成影響冈止。
1、內(nèi)存緩存及磁盤緩存
1.內(nèi)存緩存的處理由NSCache對象實現(xiàn)候齿,NSCache類似一個集合的容器熙暴,它存儲key-value對闺属,類似于nsdictionary類,我們通常使用緩存來臨時存儲短時間使用但創(chuàng)建昂貴的對象周霉,重用這些對象可以優(yōu)化新能掂器,同時這些對象對于程序來說不是緊要的,如果內(nèi)存緊張就會自動釋放俱箱。
2.磁盤緩存的處理使用NSFileManager對象實現(xiàn)国瓮,圖片存儲的位置位于cache文件夾,另外SDImageCache還定義了一個串行隊列來異步存儲圖片狞谱。
3.SDImageCache提供了大量方法來緩存乃摹、獲取、移除及清空圖片跟衅。對于圖片的索引孵睬,我們通過一個key來索引,在內(nèi)存中伶跷,我們將其作為NSCache的key值掰读,而在磁盤中,我們用這個key值作為圖片的文件名叭莫,對于一個遠(yuǎn)程下載的圖片其url實作為這個key的最佳選擇蹈集。
2、存儲圖片
先在內(nèi)存中放置一份緩存雇初,如果需要緩存到磁盤拢肆,將磁盤緩存操作作為一個task放到串行隊列中處理,會先檢查圖片格式是jpeg還是png靖诗,將其轉(zhuǎn)換為響應(yīng)的圖片數(shù)據(jù)郭怪,最后吧數(shù)據(jù)寫入磁盤中(文件名是對key值做MD5后的串)
3、查詢圖片
內(nèi)存和磁盤查詢圖片API:
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key;
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key;
查看本地是否存在key指定的圖片呻畸,使用一下API:
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
4、移除圖片
移除圖片API:
- (void)removeImageForKey:(NSString *)key;
- (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion;
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk;
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion;
5悼院、清理圖片(磁盤)
清空磁盤圖片可以選擇完全清空和部分清空伤为,完全清空就是吧緩存文件夾刪除。
- (void)clearDisk;
- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion;
部分清理 會根據(jù)設(shè)置的一些參數(shù)移除部分文件据途,主要有兩個指標(biāo):文件的緩存有效期(maxCacheAge:默認(rèn)是1周)和最大緩存空間大薪视蕖(maxCacheSize:如果所有文件大小大于最大值,會按照文件最后修改時間的逆序颖医,以每次一半的遞歸來移除哪些過早的文件位衩,知道緩存文件總大小小于最大值),具體代碼參考- (void)cleanDiskWithCompletionBlock熔萧;
6糖驴、小結(jié)
SDImageCache處理提供以上API僚祷,還提供了獲取緩存大小,緩存中圖片數(shù)量等API贮缕,
常用的接口和屬性:
(1)-getSize :獲得硬盤緩存的大小
(2)-getDiskCount : 獲得硬盤緩存的圖片數(shù)量
(3)-clearMemory : 清理所有內(nèi)存圖片
(4)- removeImageForKey:(NSString *)key 系列的方法 : 從內(nèi)存辙谜、硬盤按要求指定清除圖片
(5)maxMemoryCost : 保存在存儲器中像素的總和
(6)maxCacheSize : 最大緩存大小 以字節(jié)為單位。默認(rèn)沒有設(shè)置感昼,也就是為0装哆,而清理磁盤緩存的先決條件為self.maxCacheSize > 0,所以0表示無限制定嗓。
(7)maxCacheAge : 在內(nèi)存緩存保留的最長時間以秒為單位計算蜕琴,默認(rèn)是一周
三、SDWebImageManager
實際使用中并不直接使用SDWebImageDownloader和SDImageCache類對圖片進(jìn)行下載和存儲宵溅,而是使用SDWebImageManager來管理凌简。包括平常使用UIImageView+WebCache等控件的分類,都是使用SDWebImageManager來處理层玲,該對象內(nèi)部定義了一個圖片下載器(SDWebImageDownloader)和圖片緩存(SDImageCache)
@interface SDWebImageManager : NSObject
@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
...
@end
SDWebImageManager聲明了一個delegate屬性号醉,其實是一個id<SDWebImageManagerDelegate>對象,代理聲明了兩個方法
// 控制當(dāng)圖片在緩存中沒有找到時辛块,應(yīng)該下載哪個圖片
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
// 允許在圖片已經(jīng)被下載完成且被緩存到磁盤或內(nèi)存前立即轉(zhuǎn)換
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
這兩個方法會在SDWebImageManager的-downloadImageWithURL:options:progress:completed:方法中調(diào)用畔派,而這個方法是SDWebImageManager類的核心所在(具體看源碼)
SDWebImageManager的幾個API:
(1)- (void)cancelAll : 取消runningOperations中所有的操作,并全部刪除
(2)- (BOOL)isRunning :檢查是否有操作在運行润绵,這里的操作指的是下載和緩存組成的組合操作
(3) - downloadImageWithURL:options:progress:completed: 核心方法
(4)- (BOOL)diskImageExistsForURL:(NSURL *)url :指定url的圖片是否進(jìn)行了磁盤緩存
四线椰、視圖擴(kuò)展
在使用SDWebImage的時候,使用最多的是UIImageView+WebCache中的針對UIImageView的擴(kuò)展尘盼,核心方法是sd_setImageWithURL:placeholderImage:options:progress:completed:憨愉, 其使用SDWebImageManager單例對象下載并緩存圖片。
除了擴(kuò)展UIImageView外卿捎,SDWebImage還擴(kuò)展了UIView配紫,UIButton,MKAnnotationView等視圖類午阵,具體可以參考源碼躺孝,除了可以使用擴(kuò)展的方法下載圖片,同時也可以使用SDWebImageManager下載圖片底桂。
UIView+WebCacheOperation分類:
把當(dāng)前view對應(yīng)的圖片操作對象存儲起來(通過運行時設(shè)置屬性)植袍,在基類中完成
存儲的結(jié)構(gòu):一個loadOperationKey屬性,value是一個字典(字典結(jié)構(gòu): key:UIImageViewAnimationImages或者UIImageViewImageLoad籽懦,value是 operation數(shù)組(動態(tài)圖片)或者對象)
UIButton+WebCache分類
會根據(jù)不同的按鈕狀態(tài)于个,下載的圖片根據(jù)不同的狀態(tài)進(jìn)行設(shè)置
imageURLStorageKey:{state:url}
五、技術(shù)點
- 1.dispatch_barrier_sync函數(shù)暮顺,用于對操作設(shè)置順序厅篓,確保在執(zhí)行完任務(wù)后再確保后續(xù)操作秀存。常用于確保線程安全性操作
- 2.NSMutableURLRequest:用于創(chuàng)建一個網(wǎng)絡(luò)請求對象,可以根據(jù)需要來配置請求報頭等信息
- 3.NSOperation及NSOperationQueue:操作隊列是OC中一種告誡的并發(fā)處理方法贷笛,基于GCD實現(xiàn)应又,相對于GCD來說,操作隊列的優(yōu)點是可以取消在任務(wù)處理隊列中的任務(wù)乏苦,另外在管理操作間的依賴關(guān)系方面容易一些株扛,對SDWebImage中我們看到如何使用依賴將下載順序設(shè)置成后進(jìn)先出的順序
- 4.NSURLSession:用于網(wǎng)絡(luò)請求及相應(yīng)處理
- 5.開啟后臺任務(wù)
- 6.NSCache類:一個類似于集合的容器,存儲key-value對汇荐,這一點類似于nsdictionary類洞就,我們通常用使用緩存來臨時存儲短時間使用但創(chuàng)建昂貴的對象。重用這些對象可以優(yōu)化性能掀淘,因為它們的值不需要重新計算旬蟋。另外一方面,這些對象對于程序來說不是緊要的革娄,在內(nèi)存緊張時會被丟棄
- 7.清理緩存圖片的策略:特別是最大緩存空間大小的設(shè)置倾贰。如果所有緩存文件的總大小超過這一大小,則會按照文件最后修改時間的逆序拦惋,以每次一半的遞歸來移除那些過早的文件匆浙,直到緩存的實際大小小于我們設(shè)置的最大使用空間。
- 8.圖片解壓操作:這一操作可以查看SDWebImageDecoder.m中+decodedImageWithImage方法的實現(xiàn)厕妖。
- 9.對GIF圖片的處理
- 10.對WebP圖片的處理首尼。
收錄:原文地址
以下文章可以做一個學(xué)習(xí)參考:
GCD面試要點
block面試要點
Runtime面試要點
RunLoop面試要點
內(nèi)存管理面試要點
MVC、MVVM面試要點
網(wǎng)絡(luò)性能優(yōu)化面試要點
網(wǎng)絡(luò)編程面試要點
KVC&KVO面試要點
數(shù)據(jù)存儲面試要點
混編技術(shù)面試要點
設(shè)計模式面試要點
UI面試要點