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