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 的錯誤域,用于輸出錯誤信息。