SDWebImage源碼閱讀筆記

SDWebImage的結構
首先來看SDWebImageManager類,頭文件中有如下內容:
SDWebImageOptions

定義基本的配置選項,簡單翻譯了一下注釋

  • SDWebImageRetryFailed 默認,當從一個URL下載失敗,這個URL會被加入黑名單,之后不會重試。不過黑名單是存在內存中的,所以當程序下次運行時還是有機會重新嘗試下載這個圖片的。
  • SDWebImageLowPriority 默認,圖片會在UI交互進行交互的時候下載,這個選項可以禁用這個特性,將下載延遲到UIScrollView停止滾動之后
  • SDWebImageCacheMemoryOnly 禁用磁盤緩存
  • SDWebImageProgressiveDownload 變下載邊顯示,默認是下載完成后才顯示
  • SDWebImageRefreshCached即使圖片被緩存,也會遵守HTTP響應緩存控制,在遠端刷新時重新下載。SDWebImage磁盤緩存管理將被NSURLCache代替,這將導致輕微的性能下降。這個選項有助于處理同一個URL下圖片不同的情況。 如果緩存圖片被刷新,完成的block回調被已緩存的圖片和最終的圖片各調用一次。
  • SDWebImageContinueInBackground 在iOS4以上系統,啟用后臺下載
  • SDWebImageHandleCookies cookie管理
  • SDWebImageAllowInvalidSSLCertificates 允許不受信任的SSL證書,用于測試。
  • SDWebImageHighPriority 默認的,圖片按順序加載,這個選項將圖片移動到隊列最前面
  • SDWebImageDelayPlaceholder 默認的,占位圖在圖片加載時加載,這個選項會延遲占位圖的加載到圖片完成加載之后
  • SDWebImageTransformAnimatedImage 由于大多數轉化代碼可能會損壞圖片動畫,通常是不對其調用transformDownloadedImage 代理方法,使用這個枚舉來啟用
  • SDWebImageAvoidAutoSetImage 默認情況,圖片會在下載后添加到imageView,這個選項允許你手動管理圖片當圖片下載好之后。

接下來是代理SDWebImageManagerDelegate的定義:
-(BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;

當這個圖片不在緩存中,將要被下載時調用

-(UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)imagewithURL:(NSURL *)imageURL;

允許圖片在被下載完成后緩存到磁盤和內存之前立即被轉換(轉換transform應該就是將二進制數據格式化吧我猜)。這個方法在子線程執行以防止阻礙主線程。

接下來是一段簡單的使用說明:
SDWebImageManager是其他category的前置類,即其他category都是使用SDWebImageManager進行下載圖片的。SDWebImageManager將下載器(SDWebImageDownloader)和緩存(SDImageCache)鏈接起來。你可以使用這個類直接下載和緩存圖片,而不需要使用UIView,例如

[managerdownloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOLfinished, NSURL *imageURL) {
    if(image) {
      // do something with image
    }
}];

然后是SDWebImageManager的屬性和方法的定義。值得說明的是:

@property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;

緩存過濾器是一個block,SDWebImageManager需要將一個URL轉換為緩存的key時使用它。它可以移除URL的動態部分,下面是例子:

[[SDWebImageManagersharedManager] setCacheKeyFilter:^(NSURL *url) {
   url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
   return [url absoluteString];
}];
    

其他的方法基本上都是見名知義的,就不需要過多解釋了。來到.m文件,三百多行代碼中有足足180行是

- (id <SDWebImageOperation>)downloadImageWithURL:options:progress:completed:方法的實現,所以只要看看這個方法即可。

首先是一個斷言(我自己幾乎從來沒用過斷言,以后應該改進啊),當completed block為空的時候會觸發斷言。然后作者非常周全的考慮到了很多人會犯的一個錯誤是將string直接作為URL參數傳入,XCode不會拋出警告,所以作者在這里判斷并將字符串作為參數初始化一個NSURL對象并賦值給url。然后又判斷url參數是否為NSURL,以防止被傳入一個錯誤的類型。

接下來,作者使用線程鎖檢查url是否在黑名單中,并判斷url的長度是否為0,最后再對參數做一次檢查??。然后將當前的操作添加到一個集合中去,用于取消下載等操作。

終于到正戲了,首先檢查磁盤緩存,細節我就不每一行都解釋了,包括是否操作被取消了,即時調用代理方法,根據配置做不同的操作等等,基本都是邏輯判斷了。最后返回操作對象。

迫不及待要看看平時最常用的UIImageView+WebCache這個分類了,看看頭文件,方法不多,而且功能都很具體,直接看最常用的- (void)sd_setImageWithURL:(NSURL*)url;方法吧。

嗯,只有一句,[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];這個在意料之中的,平時自己封裝工具也經常這么干。點進去接著看。

這下進入正菜了。首先取消當前的加載任務,因為是ImageView 的分類,一個ImageView自然只需要加載一個image,很好,繼續。runtime閃亮登場!objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);這個也是runtime里很常用的一個函數,將一個屬性綁定給一個對象。這里將url綁定給了imageView,這樣imageView就有了url這個屬性。接下來處理了一下占位圖和ActivityIndicatorView。然后果然看到了SDWebImageManager的- (id <SDWebImageOperation>)downloadImageWithURL:options:progress:completed:方法。然后就是在完成的回調里面各種判斷和執行完成回調了。

可以看到,SDWebImage的設計方式很合理,首先定義基本的管理類來管理這個工具的核心功能——對于SDWebImage就是下載(SDWebImageDownloader)和緩存(SDImageCache)。具體的功能分別在對應的類中實現。最后通過分類的形式創建出具體方便的使用方式和場景。一般的工具類都可以借鑒這種設計方式。

最后附帶一個SDWebImageCompat類的簡介,對于想要公開的代碼庫,兼容性是很重要的問題,而這些內容在一般的具體業務中很少被考慮到。

#ifdef __OBJC_GC__
#errorSDWebImage does not support Objective-C Garbage Collection
#endif
//不支持OC的垃圾回收機制
#if IPHONE_OS_VERSION_MIN_REQUIRED != 20000 &&IPHONE_OS_VERSION_MIN_REQUIRED < _IPHONE5_0
#errorSDWebImage doesn't support Deployment Target version < 5.0
#endif
//不支持iOS5以前的版本
#if!TARGET_OS_IPHONE
#import <AppKit/AppKit.h>
#ifndefUIImage
#defineUIImage NSImage
#endif
#ifndefUIImageView
#defineUIImageView NSImageView
#endif
#else
//在Mac下將UIKit控件定義為AppKit控件,用于支持macOS

#ifndefNS_ENUM
#defineNS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif

#ifndefNS_OPTIONS
#defineNS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
//定義 NS_ENUM 和 NS_OPTIONS(用于支持較早的OC版本?)

#ifOS_OBJECT_USE_OBJC
   #undef SDDispatchQueueRelease
   #undef SDDispatchQueueSetterSementics
   #define SDDispatchQueueRelease(q)
   #define SDDispatchQueueSetterSementics strong
#else
#undefSDDispatchQueueRelease
#undefSDDispatchQueueSetterSementics
#defineSDDispatchQueueRelease(q) (dispatch_release(q))
#defineSDDispatchQueueSetterSementics assign
#endif
//定義了兩個類型,但是不明白為什么要這么定義??

#if!__has_feature(objc_arc)
#errorSDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arcflag
#endif
//聲明SDWebImage 只支持ARC
 
NSString *constSDWebImageErrorDomain = @"SDWebImageErrorDomain";
//最后定義了SDWebImage 的錯誤域,用于輸出錯誤信息。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容