在 iOS 的圖片加載框架中,SDWebImage 可謂是占據大半壁江山。它支持從網絡中下載且緩存圖片,并設置圖片到對應的 UIImageView 控件或者 UIButton 控件。在項目中使用 SDWebImage 來管理圖片加載相關操作可以極大地提高開發效率,讓我們更加專注于業務邏輯實現。
SDWebImage 概論
1.提供了一個 UIImageView 的 category 用來加載網絡圖片并且對網絡圖片的緩存進行管理
2.采用異步方式來下載網絡圖片
3.采用異步方式,使用 memory+disk 來緩存網絡圖片,自動管理緩存。
4.支持 GIF 動畫
5.支持 WebP 格式
6.同一個 URL 的網絡圖片不會被重復下載
7.失效的 URL 不會被無限重試
8.耗時操作都在子線程,確保不會阻塞主線程
9.使用 GCD 和 ARC
10.支持 Arm64
SDWebImage 使用
1.使用 ImageView+WebCache category 來加載 UITableView 中 cell 的圖片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
2.使用 block,采用這個方案可以在網絡圖片加載過程中得知圖片的下載進度和圖片加載成功與否
[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 的實現提供接口。
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 方式,但那個并不是我們經常用到的。基本上面所講的3個方法都能滿足需求。
SDWebImage 流程
SDWebImage 接口
SDWebImage 是一個成熟而且比較龐大的框架,但是在使用過程中并不需要太多的接口,這算是一種代碼封裝程度的體現。這里就介紹比較常用的幾個接口。
-
給 UIImageView 設置圖片的接口,SDWebImage 有提供多個給UIImageView 設置圖片的接口,最終所有的接口都會調用下圖的這個接口,這是大多數框架的做法。
給UIImageView設置圖片的接口 獲取 SDWebImage 的磁盤緩存大小,在項目中有時候會需要統計應用的磁盤緩存內容大小,那么獲取圖片的緩存大小就是使用這個接口來實現
[SDImageCache sharedImageCache] getSize];
- 清理內存緩存,清理內存中緩存的圖片資源,釋放內存資源。
[[SDImageCache sharedImageCache] clearMemory];
- 有了清理內存緩存,自然也有清理磁盤緩存的接口
[[SDImageCache sharedImageCache] clearDisk];
SDWebImage 解析
解析主要圍繞著 SDWebImage 的圖片加載流程來分析,介紹SDWebImage 這個框架加載圖片過程中的一些處理方法和設計思路。
-
給 UIImageView 設置圖片,然后 SDWebImage 調用這個最終的圖片加載方法。
1 給UIImageView設置圖片 開始加載之前圖片先取消對應的 UIImageView 先前的圖片下載操作。試想,如果我們給 UIImageView 設置了一張新的圖片,那么我們還會在意該 UIImageVIew 先前是要加載哪一張圖片么?應該是不在意的吧!那是不是應該嘗試把該 UIImageView 先前的加載圖片相關操作給取消掉呢?
[self sd_cancelCurrentImageLoad]
該方法經過周轉,最后調用了以下方法,框架將圖片對應的下載操作放到 UIView 的一個自定義字典屬性 (operationDictionary) 中,取消下載操作第一步也是從這個 UIView 的自定義字典屬性 (operationDictionary)中取出所有的下載操作,然后依次調用取消方法,最后將取消的操作從(operationDictionary) 字典屬性中移除。
3.移除之前沒用的圖片下載操作之后就創建一個新的圖片下載操作,然后設置到 UIView 的一個自定義字典屬性 (operationDictionary) 中。
4.看看如何創建一個新的圖片下載操作,框架保存了一個失效的 url 列表,如果 url 失效了就會被加入這個列表,保證不會重復多次請求失效的 url。
根據給定的 url 生成一個唯一的 key ,之后利用這個 key 到緩存中查找對應的圖片緩存。
5.讀取圖片緩存,根據 key 先從內存中讀取圖片緩存,若沒有命中內存緩存則讀取磁盤緩存,如果磁盤緩存命中,那么將磁盤緩存讀到內存中成為內存緩存。如果都沒有命中緩存的話,那么就在執行的 doneBlock中開始下載圖片。
6.圖片下載操作完成后會將圖片對應的數據通過 completedBlock 進行回調
在圖片下載方法中,調用了一個方法用于添加創建和下載過程中的各類block 回調。
添加該 url 加載過程的狀態回調 block
如果該 url 是第一次加載的話,那么就會執行 createCallback 這個回調block ,然后在 createCallback 里面開始構建網絡請求,在下載過程中執行各類進度 block 回調。
7.當圖片下載完成之后會回到 done 的 block 回調中做圖片轉換處理和緩存操作
回到 UIImageView 控件的設置圖片方法 block 回調中,給對應的UIImageView 設置圖片,操作流程到此完成。
8.304 的處理
SDWebImage在加載圖片網絡請求的 NSURLConnection 的代理中對httpCode 做了判斷,當 httpCode 為 304 的時候放棄下載,讀取緩存。
總結
SDWebImage 作為一個優秀的圖片加載框架,提供的使用方法和接口對開發者來說非常友好。其內部實現多是采用 block 的方式來實現回調,代碼閱讀起來可能沒有那么直觀。此文章旨在給大家講解 SDWebImage 這個框架的圖片大概加載流程,其中具體細節限于篇幅無法詳細深究。能力有限,文章中難免有錯誤,若大家在閱讀過程中有發現不合理或者錯誤的地方懇請在評論中指出,我會在第一時間進行修正,不勝感激。