在 iOS 的圖片加載框架中,SDWebImage 可謂是占據(jù)大半壁江山。它支持從網(wǎng)絡(luò)中下載且緩存圖片,并設(shè)置圖片到對(duì)應(yīng)的 UIImageView 控件或者 UIButton 控件。在項(xiàng)目中使用 SDWebImage 來(lái)管理圖片加載相關(guān)操作可以極大地提高開發(fā)效率,讓我們更加專注于業(yè)務(wù)邏輯實(shí)現(xiàn)。
SDWebImage 概論
1.提供了一個(gè) UIImageView 的 category 用來(lái)加載網(wǎng)絡(luò)圖片并且對(duì)網(wǎng)絡(luò)圖片的緩存進(jìn)行管理
2.采用異步方式來(lái)下載網(wǎng)絡(luò)圖片
3.采用異步方式,使用 memory+disk 來(lái)緩存網(wǎng)絡(luò)圖片,自動(dòng)管理緩存。
4.支持 GIF 動(dòng)畫
5.支持 WebP 格式
6.同一個(gè) URL 的網(wǎng)絡(luò)圖片不會(huì)被重復(fù)下載
7.失效的 URL 不會(huì)被無(wú)限重試
8.耗時(shí)操作都在子線程,確保不會(huì)阻塞主線程
9.使用 GCD 和 ARC
10.支持 Arm64
SDWebImage 使用
1.使用 ImageView+WebCache category 來(lái)加載 UITableView 中 cell 的圖片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
2.使用 block,采用這個(gè)方案可以在網(wǎng)絡(luò)圖片加載過(guò)程中得知圖片的下載進(jìn)度和圖片加載成功與否
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
//... completion code here ...
}];
3.使用 SDWebImageManager,SDWebImageManager 為UIImageView+WebCache category 的實(shí)現(xiàn)提供接口。
SDWebImageManager *manager = [SDWebImageManager sharedManager] ;
[manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
// progression tracking code
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
}
}];
4.加載圖片還有使用 SDWebImageDownloader 和 SDImageCache 方式,但那個(gè)并不是我們經(jīng)常用到的?;旧厦嫠v的3個(gè)方法都能滿足需求。
SDWebImage 流程

SDWebImage 接口
SDWebImage 是一個(gè)成熟而且比較龐大的框架,但是在使用過(guò)程中并不需要太多的接口,這算是一種代碼封裝程度的體現(xiàn)。這里就介紹比較常用的幾個(gè)接口。
-
給 UIImageView 設(shè)置圖片的接口,SDWebImage 有提供多個(gè)給UIImageView 設(shè)置圖片的接口,最終所有的接口都會(huì)調(diào)用下圖的這個(gè)接口,這是大多數(shù)框架的做法。
給UIImageView設(shè)置圖片的接口 獲取 SDWebImage 的磁盤緩存大小,在項(xiàng)目中有時(shí)候會(huì)需要統(tǒng)計(jì)應(yīng)用的磁盤緩存內(nèi)容大小,那么獲取圖片的緩存大小就是使用這個(gè)接口來(lái)實(shí)現(xiàn)
[SDImageCache sharedImageCache] getSize];
- 清理內(nèi)存緩存,清理內(nèi)存中緩存的圖片資源,釋放內(nèi)存資源。
[[SDImageCache sharedImageCache] clearMemory];
- 有了清理內(nèi)存緩存,自然也有清理磁盤緩存的接口
[[SDImageCache sharedImageCache] clearDisk];
SDWebImage 解析
解析主要圍繞著 SDWebImage 的圖片加載流程來(lái)分析,介紹SDWebImage 這個(gè)框架加載圖片過(guò)程中的一些處理方法和設(shè)計(jì)思路。
-
給 UIImageView 設(shè)置圖片,然后 SDWebImage 調(diào)用這個(gè)最終的圖片加載方法。
1 給UIImageView設(shè)置圖片 開始加載之前圖片先取消對(duì)應(yīng)的 UIImageView 先前的圖片下載操作。試想,如果我們給 UIImageView 設(shè)置了一張新的圖片,那么我們還會(huì)在意該 UIImageVIew 先前是要加載哪一張圖片么?應(yīng)該是不在意的吧!那是不是應(yīng)該嘗試把該 UIImageView 先前的加載圖片相關(guān)操作給取消掉呢?
[self sd_cancelCurrentImageLoad]

該方法經(jīng)過(guò)周轉(zhuǎn),最后調(diào)用了以下方法,框架將圖片對(duì)應(yīng)的下載操作放到 UIView 的一個(gè)自定義字典屬性 (operationDictionary) 中,取消下載操作第一步也是從這個(gè) UIView 的自定義字典屬性 (operationDictionary)中取出所有的下載操作,然后依次調(diào)用取消方法,最后將取消的操作從(operationDictionary) 字典屬性中移除。

3.移除之前沒(méi)用的圖片下載操作之后就創(chuàng)建一個(gè)新的圖片下載操作,然后設(shè)置到 UIView 的一個(gè)自定義字典屬性 (operationDictionary) 中。

4.看看如何創(chuàng)建一個(gè)新的圖片下載操作,框架保存了一個(gè)失效的 url 列表,如果 url 失效了就會(huì)被加入這個(gè)列表,保證不會(huì)重復(fù)多次請(qǐng)求失效的 url。

根據(jù)給定的 url 生成一個(gè)唯一的 key ,之后利用這個(gè) key 到緩存中查找對(duì)應(yīng)的圖片緩存。

5.讀取圖片緩存,根據(jù) key 先從內(nèi)存中讀取圖片緩存,若沒(méi)有命中內(nèi)存緩存則讀取磁盤緩存,如果磁盤緩存命中,那么將磁盤緩存讀到內(nèi)存中成為內(nèi)存緩存。如果都沒(méi)有命中緩存的話,那么就在執(zhí)行的 doneBlock中開始下載圖片。

6.圖片下載操作完成后會(huì)將圖片對(duì)應(yīng)的數(shù)據(jù)通過(guò) completedBlock 進(jìn)行回調(diào)

在圖片下載方法中,調(diào)用了一個(gè)方法用于添加創(chuàng)建和下載過(guò)程中的各類block 回調(diào)。

添加該 url 加載過(guò)程的狀態(tài)回調(diào) block

如果該 url 是第一次加載的話,那么就會(huì)執(zhí)行 createCallback 這個(gè)回調(diào)block ,然后在 createCallback 里面開始構(gòu)建網(wǎng)絡(luò)請(qǐng)求,在下載過(guò)程中執(zhí)行各類進(jìn)度 block 回調(diào)。

7.當(dāng)圖片下載完成之后會(huì)回到 done 的 block 回調(diào)中做圖片轉(zhuǎn)換處理和緩存操作

回到 UIImageView 控件的設(shè)置圖片方法 block 回調(diào)中,給對(duì)應(yīng)的UIImageView 設(shè)置圖片,操作流程到此完成。

8.304 的處理
SDWebImage在加載圖片網(wǎng)絡(luò)請(qǐng)求的 NSURLConnection 的代理中對(duì)httpCode 做了判斷,當(dāng) httpCode 為 304 的時(shí)候放棄下載,讀取緩存。

總結(jié)
SDWebImage 作為一個(gè)優(yōu)秀的圖片加載框架,提供的使用方法和接口對(duì)開發(fā)者來(lái)說(shuō)非常友好。其內(nèi)部實(shí)現(xiàn)多是采用 block 的方式來(lái)實(shí)現(xiàn)回調(diào),代碼閱讀起來(lái)可能沒(méi)有那么直觀。此文章旨在給大家講解 SDWebImage 這個(gè)框架的圖片大概加載流程,其中具體細(xì)節(jié)限于篇幅無(wú)法詳細(xì)深究。能力有限,文章中難免有錯(cuò)誤,若大家在閱讀過(guò)程中有發(fā)現(xiàn)不合理或者錯(cuò)誤的地方懇請(qǐng)?jiān)谠u(píng)論中指出,我會(huì)在第一時(shí)間進(jìn)行修正,不勝感激。

