iOS開發(fā)中經(jīng)常會用到SDW用于下載展示網(wǎng)絡(luò)圖片。那么SDW的底層是如何實(shí)現(xiàn)的?空暇之余就來整理下。
SDWebImage底層組成
1、內(nèi)存圖片緩存
2、內(nèi)存操作緩存
3、磁盤沙盒緩存
SDWebImage實(shí)現(xiàn)過程
首先看一下整個代碼的結(jié)構(gòu)圖
step1
首先從 setImageWithURL:placeholderImage:options:
進(jìn)入后會先顯示placeholderImage,然后 SDWebImageManager 根據(jù) URL 開始處理圖片。
step2
調(diào)用SDWebImageManager-downloadWithURL:delegate:options:userInfo:
,交給 SDImageCache 去緩存查找圖片是否存在queryDiskCacheForKey:delegate:userInfo:
step3
首先內(nèi)存中尋找緩存,若內(nèi)存中已經(jīng)有圖片緩存,**SDImageCacheDelegate **回調(diào) imageCache:didFindImage:forKey:userInfo:
到 SDWebImageManager。
step3.1
SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage:
到 UIImageView+WebCache 等待展示圖片。
step4
若內(nèi)存緩存中沒有,生成 NSInvocationOperation 添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存。
step4.1
根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:
。
step4.2
若上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(注意是內(nèi)存緩存中哦,如果空閑內(nèi)存過小,會先清空內(nèi)存緩存)。SDImageCacheDelegate 回調(diào)imageCache:didFindImage:forKey:userInfo:
。進(jìn)而回調(diào)展示圖片。
step4.3
如果從硬盤緩存目錄讀取不到圖片,說明所有沙盒緩存(即內(nèi)存和硬盤中均不存在)都不存在該圖片,此時回調(diào) imageCache:didNotFindImageForKey:userInfo:
下載圖片。
step5
共享或重新生成一個下載器 SDWebImageDownloader 開始下載圖片。
step5.1
圖片下載由 NSURLConnection 來做,實(shí)現(xiàn)相關(guān) delegate 來判斷圖片下載的進(jìn)程(下載進(jìn)行中、下載完成和下載失敗),connection:didReceiveData:
中利用 **ImageIO **做了按圖片下載進(jìn)度加載效果。
step5.2
connectionDidFinishLoading:
數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。圖片解碼處理在一個 NSOperationQueue 完成,不會拖慢主線程 UI。如果有需要對下載的圖片進(jìn)行二次處理,最好也在這里完成,效率會好很多。
step5.3
在主線程 notifyDelegateOnMainThreadWithInfo:
宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo:
回調(diào)給 SDWebImageDownloader。
step5.4
imageDownloader:didFinishWithImage:
回調(diào)給 SDWebImageManager 告知圖片下載完成。
step5.5
通知所有的 downloadDelegates 下載完成,回調(diào)給需要的地方展示圖片。
step5.6
將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時保存。寫文件到硬盤也在以單獨(dú) NSInvocationOperation 完成,避免拖慢主線程。
另外,SDImageCache 在初始化的時候會注冊一些消息通知,在內(nèi)存警告或退到后臺的時候清理內(nèi)存圖片緩存,應(yīng)用結(jié)束的時候清理過期圖片。
重寫與覆蓋
從上面流程可以看出,當(dāng)你調(diào)用setImageWithURL:方法的時候,他會自動去給你干這么多事,當(dāng)你需要在某一具體時刻做事情的時候,你可以覆蓋這些方法。比如在下載某個圖片的過程中要響應(yīng)一個事件,就覆蓋這個方法:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"顯示當(dāng)前進(jìn)度");
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
NSLog(@"下載完成");
}];
使用
step1 導(dǎo)入工程
step2 導(dǎo)入頭文件
step3 根據(jù)需要實(shí)現(xiàn)不同的方法
具體的不同方法查看https://github.com/rs/SDWebImage