如果說要評一個iOS開發(fā)用的最多的第三方庫轻黑,那么SDWebImage
十有八九會入選搅轿。
這個類庫提供一個 UIImageView類別
以支持加載來自網(wǎng)絡(luò)的遠(yuǎn)程圖片脊奋。具有緩存管理采郎、異步下載、同一個URL下載次數(shù)控制和優(yōu)化等特征狂魔。
接觸一個新的框架蒜埋,第一步是要學(xué)會怎么去用,接著才是看他是怎么實(shí)現(xiàn)的最楷。
在這篇文章中整份,我會帶大家一起來分析 SDWebImage
幫我們用什么方法做了那些事情,讓大家宏觀的理解這個框架籽孙,讓大家知道怎么去用這個框架烈评。
導(dǎo)入框架
首先第一步肯定是導(dǎo)入框架,然后用的比較多的就是cocoapods了犯建,然后這塊就不在這里贅述了讲冠,網(wǎng)上很多文章去介紹這塊,只要在pods里面加入以下代碼适瓦,然后update竿开,就可以把最新的SDWebImage拉下來了。
pod 'SDWebImage'
SDWebImage加載圖片流程
- 入口這個方法 會先把
placeholderImage
顯示玻熙,然后SDWebImageManager
根據(jù) URL 開始處理圖片否彩。
setImageWithURL:placeholderImage:options:
- 進(jìn)入
SDWebImageManager
這個管理者的單例
//調(diào)用下載方法
downloadWithURL:delegate:options:userInfo:
該方法會傳遞到 SDImageCache
從緩存查找圖片是否已經(jīng)下載
//從緩存查找圖片是否已經(jīng)下載
queryDiskCacheForKey:delegate:userInfo:
- 該方法會先從內(nèi)存圖片緩存查找是否有圖片,如果內(nèi)存中已經(jīng)有圖片緩存嗦随,
SDImageCacheDelegate
會通過下面的方法回調(diào)到SDWebImageManager
列荔。
imageCache:didFindImage:forKey:userInfo:
-
SDWebImageManagerDelegate
回調(diào)下面方法到 UIImageView+WebCache 等前端展示圖片。
webImageManager:didFinishWithImage:
- 如果內(nèi)存緩存中沒有枚尼,生成
NSInvocationOperation
添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存贴浙。 - 根據(jù)
URLKey
在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在NSOperation
進(jìn)行的操作署恍,所以回主線程進(jìn)行結(jié)果回調(diào)notifyDelegate:
崎溃。 - 如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小锭汛,會先清空內(nèi)存緩存)笨奠。
SDImageCacheDelegate
回調(diào)以下方法進(jìn)而回調(diào)展示圖片袭蝗。
imageCache:didFindImage:forKey:userInfo:
- 如果從硬盤緩存目錄讀取不到圖片唤殴,說明所有緩存都不存在該圖片般婆,需要下載圖片,回調(diào)
imageCache:didNotFindImageForKey:userInfo:
- 共享或重新生成一個下載器
SDWebImageDownloader
開始下載圖片朵逝。 - 圖片下載由
NSURLConnection
來做蔚袍,實(shí)現(xiàn)相關(guān)delegate
來判斷圖片下載中、下載完成和下載失敗配名。 - 利用 ImageIO 做了按圖片下載進(jìn)度加載效果啤咽。
connection:didReceiveData:
- 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
connectionDidFinishLoading:
- 圖片解碼處理在一個
NSOperationQueue
完成渠脉,不會拖慢主線程 UI宇整。如果有需要對下載的圖片進(jìn)行二次處理,最好也在這里完成芋膘,效率會好很多鳞青。 - 在主線程的以下方法通知解碼完成,
notifyDelegateOnMainThreadWithInfo:
然后通過下面方法 回調(diào)給 SDWebImageDownloader
为朋。
imageDecoder:didFinishDecodingImage:userInfo:
- 回調(diào)給 SDWebImageManager 告知圖片下載完成臂拓。
imageDownloader:didFinishWithImage:
- 通知所有的
downloadDelegates
下載完成,回調(diào)給需要的地方展示圖片习寸。 - 將圖片保存到
SDImageCache
中胶惰,內(nèi)存緩存和硬盤緩存同時(shí)保存。寫文件到硬盤也在以單獨(dú)NSInvocationOperation
完成霞溪,避免拖慢主線程孵滞。 -
SDImageCache
在初始化的時(shí)候會注冊一些消息通知,在內(nèi)存警告或退到后臺的時(shí)候清理內(nèi)存圖片緩存鸯匹,應(yīng)用結(jié)束的時(shí)候清理過期圖片剃斧。 - SDWebImage 也提供了
UIButton+WebCache
和MKAnnotationView+WebCache
,方便使用忽你。 -
SDWebImagePrefetcher
可以預(yù)先下載圖片幼东,方便后續(xù)使用。
SDWebImage庫的作用
通過對UIImageView的類別擴(kuò)展來實(shí)現(xiàn)異步加載替換圖片的工作科雳。
主要用到的對象:
-
UIImageView (WebCache)
類別根蟹,入口封裝,
- 實(shí)現(xiàn)讀取圖片完成后的回調(diào)
-
SDWebImageManager
糟秘,對圖片進(jìn)行管理的中轉(zhuǎn)站简逮,記錄那些圖片正在讀取。向下層讀取Cache(調(diào)用SDImageCache
)尿赚,或者向網(wǎng)絡(luò)讀取對象(調(diào)用SDWebImageDownloader
) 散庶。
- 實(shí)現(xiàn)SDImageCacheSDWebImageDownloader的回調(diào)蕉堰。
-
SDImageCache
,根據(jù)URL的MD5摘要對圖片進(jìn)行存儲和讀缺辍(實(shí)現(xiàn)存在內(nèi)存中或者存在硬盤上兩種實(shí)現(xiàn))
- 實(shí)現(xiàn)圖片和內(nèi)存清理工作屋讶。
-
SDWebImageDownloader
,根據(jù)URL向網(wǎng)絡(luò)讀取數(shù)據(jù)(實(shí)現(xiàn)部分讀取和全部讀取后再通知回調(diào)兩種方式)
其他類:
SDWebImageDecoder
须教,異步對圖像進(jìn)行了一次解壓??
Q&A
SDImageCache是怎么做數(shù)據(jù)管理的?
SDImageCache
分兩個部分望迎,一個是內(nèi)存層面的病袄,一個是硬盤層面的桅锄。內(nèi)存層面的相當(dāng)是個緩存器洋只,以Key-Value
的形式存儲圖片。當(dāng)內(nèi)存不夠的時(shí)候會清除所有緩存圖片贬养。用搜索文件系統(tǒng)的方式做管理挤土,文件替換方式是以時(shí)間為單位,剔除時(shí)間大于一周的圖片文件误算。當(dāng)SDWebImageManager
向SDImageCache
要資源時(shí)仰美,先搜索內(nèi)存層面的數(shù)據(jù),如果有直接返回尉桩,沒有的話去訪問磁盤筒占,將圖片從磁盤讀取出來,然后做Decoder
蜘犁,將圖片對象放到內(nèi)存層面做備份翰苫,再返回調(diào)用層。為啥必須做Decoder?
由于UIImage
的imageWithData
函數(shù)是每次畫圖的時(shí)候才將Data解壓成ARGB的圖像这橙,所以在每次畫圖的時(shí)候奏窑,會有一個解壓操作,這樣效率很低屈扎,但是只有瞬時(shí)的內(nèi)存需求埃唯。為了提高效率通過SDWebImageDecoder
將包裝在Data下的資源解壓,然后畫在另外一張圖片上鹰晨,這樣這張新圖片就不再需要重復(fù)解壓了墨叛。
這種做法是典型的空間換時(shí)間的做法。