重讀SDWebImage
入題簡(jiǎn)介
SDWebImage 提供了 UIImageView、UIButton 、MKAnnotationView 的圖片下載分類(lèi),只要一行代碼就可以實(shí)現(xiàn)圖片異步下載和緩存功能。
功能簡(jiǎn)介
- 一個(gè)添加了web圖片加載和緩存管理的UIImageView分類(lèi)
- 一個(gè)異步圖片下載器
- 一個(gè)異步的內(nèi)存加磁盤(pán)綜合存儲(chǔ)圖片并且自動(dòng)處理過(guò)期圖片
- 支持動(dòng)態(tài)gif圖
- 4.0 之前的動(dòng)圖效果并不是太好
- 4.0 以后基于 FLAnimatedImage加載動(dòng)圖
- 支持webP格式的圖片
- 后臺(tái)圖片解壓處理
- 確保同樣的圖片url不會(huì)下載多次
- 確保偽造的圖片url不會(huì)重復(fù)嘗試下載
- 確保主線程不會(huì)阻塞
實(shí)現(xiàn)原理
-
架構(gòu)圖(UML 類(lèi)圖)
架構(gòu)圖.png 流程圖(方法調(diào)用順序圖)

流程圖.png
目錄結(jié)構(gòu)
- Downloader
- SDWebImageDownloader
- SDWebImageDownloaderOperation
- Cache
- SDImageCache
- Utils
- SDWebImageManager
- SDWebImageDecoder
- SDWebImagePrefetcher
- Categories
- UIView+WebCacheOperation
- UIImageView+WebCache
- UIImageView+HighlightedWebCache
- UIButton+WebCache
- MKAnnotationView+WebCache
- NSData+ImageContentType
- UIImage+GIF
- UIImage+MultiFormat
- UIImage+WebP
- Other
- SDWebImageOperation(協(xié)議)
- SDWebImageCompat(宏定義、常量、通用函數(shù))
| 類(lèi)名 | 功能 |
|---|---|
| SDWebImageDownloader | 是專(zhuān)門(mén)用來(lái)下載圖片和優(yōu)化圖片加載的,跟緩存沒(méi)有關(guān)系 |
SDWebImageDownloaderOperation |
繼承于 NSOperation,用來(lái)處理下載任務(wù)的 |
SDImageCache |
用來(lái)處理內(nèi)存緩存和磁盤(pán)緩存(可選)的,其中磁盤(pán)緩存是異步進(jìn)行的,因此不會(huì)阻塞主線程 |
SDWebImageManager |
作為 UIImageView+WebCache 背后的默默付出者,主要功能是將圖片下載(SDWebImageDownloader)和圖片緩存(SDImageCache)兩個(gè)獨(dú)立的功能組合起來(lái) |
SDWebImageDecoder |
圖片解碼器,用于圖片下載完成后進(jìn)行解碼 |
| SDWebImagePrefetcher | 預(yù)下載圖片,方便后續(xù)使用,圖片下載的優(yōu)先級(jí)低,其內(nèi)部由 SDWebImageManager 來(lái)處理圖片下載和緩存 |
| UIView+WebCacheOperation | 用來(lái)記錄圖片加載的 operation,方便需要時(shí)取消和移除圖片加載的 operation |
| UIImageView+WebCache | 集成 SDWebImageManager 的圖片下載和緩存功能到 UIImageView 的方法中,方便調(diào)用方的簡(jiǎn)單使用 |
| UIImageView+HighlightedWebCache | 跟 UIImageView+WebCache 類(lèi)似,也是包裝了 SDWebImageManager,只不過(guò)是用于加載 highlighted 狀態(tài)的圖片 |
UIButton+WebCache |
跟 UIImageView+WebCache 類(lèi)似,集成 SDWebImageManager 的圖片下載和緩存功能到 UIButton 的方法中,方便調(diào)用方的簡(jiǎn)單使用 |
| MKAnnotationView+WebCache | 跟 UIImageView+WebCache 類(lèi)似 |
| NSData+ImageContentType | 用于獲取圖片數(shù)據(jù)的格式(JPEG、PNG等) |
| UIImage+GIF | 用于加載 GIF 動(dòng)圖 |
| UIImage+MultiFormat | 根據(jù)不同格式的二進(jìn)制數(shù)據(jù)轉(zhuǎn)成 UIImage 對(duì)象 |
| UIImage+WebP | 用于解碼并加載 WebP 圖片 |
工作流程

工作流程.png
- 入口
setImageWithURL:placeholderImage:options:會(huì)先把placeholderImage顯示,然后SDWebImageManager根據(jù) URL 開(kāi)始處理圖片。 - 進(jìn)入
SDWebImageManager-downloadWithURL:delegate:options:userInfo:交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載queryDiskCacheForKey:delegate:userInfo:。 - 先從內(nèi)存圖片緩存查找是否有圖片,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào)
imageCache:didFindImage:forKey:userInfo:到 SDWebImageManager。 -
SDWebImageManagerDelegate回調(diào)webImageManager:didFinishWithImage:到 UIImageView+WebCache 等前端展示圖片。 - 如果內(nèi)存緩存中沒(méi)有,生成
NSInvocationOperation添加到隊(duì)列開(kāi)始從硬盤(pán)查找圖片是否已經(jīng)緩存。 - 根據(jù)
URLKey在硬盤(pán)緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào)notifyDelegate:。 - 如果從硬盤(pán)讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過(guò)小,會(huì)先清空內(nèi)存緩存)。
SDImageCacheDelegate回調(diào)imageCache:didFindImage:forKey:userInfo:進(jìn)而回調(diào)展示圖片。 - 如果從硬盤(pán)緩存目錄讀取不到圖片,說(shuō)明所有緩存都不存在該圖片,需要下載圖片,回調(diào)
imageCache:didNotFindImageForKey:userInfo:。 - 共享或重新生成一個(gè)下載器
SDWebImageDownloader開(kāi)始下載圖片。 - 圖片下載由
NSURLConnection(3.8.0之后使用了NSURLSession),實(shí)現(xiàn)相關(guān) delegate 來(lái)判斷圖片下載中、下載完成和下載失敗。 -
connection:didReceiveData:中利用ImageIO做了按圖片下載進(jìn)度加載效果。connectionDidFinishLoading:數(shù)據(jù)下載完成后交給SDWebImageDecoder做圖片解碼處理。 - 圖片解碼處理在一個(gè)
NSOperationQueue完成,不會(huì)拖慢主線程 UI。如果有需要對(duì)下載的圖片進(jìn)行二次處理,最好也在這里完成,效率會(huì)好很多。 - 在主線程
notifyDelegateOnMainThreadWithInfo:宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo:回調(diào)給SDWebImageDownloader。 -
imageDownloader:didFinishWithImage:回調(diào)給 SDWebImageManager 告知圖片下載完成。 - 通知所有的
downloadDelegates下載完成,回調(diào)給需要的地方展示圖片。 - 將圖片保存到
SDImageCache中,內(nèi)存緩存和硬盤(pán)緩存同時(shí)保存。寫(xiě)文件到硬盤(pán)也在以單獨(dú)NSInvocationOperation完成,避免拖慢主線程。 - SDImageCache 在初始化的時(shí)候會(huì)注冊(cè)一些消息通知,在內(nèi)存警告或退到后臺(tái)的時(shí)候清理內(nèi)存圖片緩存,應(yīng)用結(jié)束的時(shí)候清理過(guò)期圖片。
-
SDWebImagePrefetcher可以預(yù)先下載圖片,方便后續(xù)使用。
常見(jiàn)問(wèn)題
- 圖片文件緩存的時(shí)間有多長(zhǎng):
1周
_maxCacheAge = kDefaultCacheMaxCacheAge
- SDWebImage 的內(nèi)存緩存是用什么實(shí)現(xiàn)的?
NSCache
- SDWebImage 的最大并發(fā)數(shù)是多少?
maxConcurrentDownloads = 6 是程序固定死了,可以通過(guò)屬性進(jìn)行調(diào)整!
- SDWebImage 支持動(dòng)圖嗎?GIF
#import <ImageIO/ImageIO.h>
[UIImage animatedImageWithImages:images duration:duration];
- SDWebImage是如何區(qū)分不同格式的圖像的
根據(jù)圖像數(shù)據(jù)第一個(gè)字節(jié)來(lái)判斷的!
PNG:壓縮比沒(méi)有JPG高,但是無(wú)損壓縮,解壓縮性能高,蘋(píng)果推薦的圖像格式!
JPG:壓縮比最高的一種圖片格式,有損壓縮!最多使用的場(chǎng)景,照相機(jī)!解壓縮的性能不好!
GIF:序列楨動(dòng)圖,特點(diǎn):只支持256種顏色!最流行的時(shí)候在1998~1999,有專(zhuān)利的!
- SDWebImage 緩存圖片的名稱是怎么確定的!
md5如果單純使用 文件名保存,重名的幾率很高! 使用 MD5 的散列函數(shù)!對(duì)完整的 URL 進(jìn)行 md5,結(jié)果是一個(gè) 32 個(gè)字符長(zhǎng)度的字符串!
-
SDWebImage的內(nèi)存警告是如何處理的!
- 利用通知中心觀察
-
- UIApplicationDidReceiveMemoryWarningNotification接收到內(nèi)存警告的通知 - 執(zhí)行
clearMemory方法,清理內(nèi)存緩存! -
- UIApplicationWillTerminateNotification接收到應(yīng)用程序?qū)⒁K止通知 - 執(zhí)行
cleanDisk方法,清理磁盤(pán)緩存! -
- UIApplicationDidEnterBackgroundNotification接收到應(yīng)用程序進(jìn)入后臺(tái)通知 - 執(zhí)行
backgroundCleanDisk方法,后臺(tái)清理磁盤(pán)! - 通過(guò)以上通知監(jiān)聽(tīng),能夠保證緩存文件的大小始終在控制范圍之內(nèi)!
-
clearDisk清空磁盤(pán)緩存,將所有緩存目錄中的文件,全部刪除!
實(shí)際工作,將緩存目錄直接刪除,再次創(chuàng)建一個(gè)同名空目錄!
