
SDWebImageOptions
定義基本的配置選項,簡單翻譯了一下注釋
- SDWebImageRetryFailed 默認(rèn),當(dāng)從一個URL下載失敗,這個URL會被加入黑名單,之后不會重試。不過黑名單是存在內(nèi)存中的,所以當(dāng)程序下次運行時還是有機會重新嘗試下載這個圖片的。
- SDWebImageLowPriority 默認(rèn),圖片會在UI交互進行交互的時候下載,這個選項可以禁用這個特性,將下載延遲到UIScrollView停止?jié)L動之后
- SDWebImageCacheMemoryOnly 禁用磁盤緩存
- SDWebImageProgressiveDownload 變下載邊顯示,默認(rèn)是下載完成后才顯示
- SDWebImageRefreshCached即使圖片被緩存,也會遵守HTTP響應(yīng)緩存控制,在遠(yuǎn)端刷新時重新下載。SDWebImage磁盤緩存管理將被NSURLCache代替,這將導(dǎo)致輕微的性能下降。這個選項有助于處理同一個URL下圖片不同的情況。 如果緩存圖片被刷新,完成的block回調(diào)被已緩存的圖片和最終的圖片各調(diào)用一次。
- SDWebImageContinueInBackground 在iOS4以上系統(tǒng),啟用后臺下載
- SDWebImageHandleCookies cookie管理
- SDWebImageAllowInvalidSSLCertificates 允許不受信任的SSL證書,用于測試。
- SDWebImageHighPriority 默認(rèn)的,圖片按順序加載,這個選項將圖片移動到隊列最前面
- SDWebImageDelayPlaceholder 默認(rèn)的,占位圖在圖片加載時加載,這個選項會延遲占位圖的加載到圖片完成加載之后
- SDWebImageTransformAnimatedImage 由于大多數(shù)轉(zhuǎn)化代碼可能會損壞圖片動畫,通常是不對其調(diào)用transformDownloadedImage 代理方法,使用這個枚舉來啟用
- SDWebImageAvoidAutoSetImage 默認(rèn)情況,圖片會在下載后添加到imageView,這個選項允許你手動管理圖片當(dāng)圖片下載好之后。
接下來是代理SDWebImageManagerDelegate的定義:
-(BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
當(dāng)這個圖片不在緩存中,將要被下載時調(diào)用
-(UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)imagewithURL:(NSURL *)imageURL;
允許圖片在被下載完成后緩存到磁盤和內(nèi)存之前立即被轉(zhuǎn)換(轉(zhuǎn)換transform應(yīng)該就是將二進制數(shù)據(jù)格式化吧我猜)。這個方法在子線程執(zhí)行以防止阻礙主線程。
接下來是一段簡單的使用說明:
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轉(zhuǎn)換為緩存的key時使用它。它可以移除URL的動態(tài)部分,下面是例子:
[[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:方法的實現(xiàn),所以只要看看這個方法即可。
首先是一個斷言(我自己幾乎從來沒用過斷言,以后應(yīng)該改進?。?,當(dāng)completed block為空的時候會觸發(fā)斷言。然后作者非常周全的考慮到了很多人會犯的一個錯誤是將string直接作為URL參數(shù)傳入,XCode不會拋出警告,所以作者在這里判斷并將字符串作為參數(shù)初始化一個NSURL對象并賦值給url。然后又判斷url參數(shù)是否為NSURL,以防止被傳入一個錯誤的類型。
接下來,作者使用線程鎖檢查url是否在黑名單中,并判斷url的長度是否為0,最后再對參數(shù)做一次檢查??。然后將當(dāng)前的操作添加到一個集合中去,用于取消下載等操作。
終于到正戲了,首先檢查磁盤緩存,細(xì)節(jié)我就不每一行都解釋了,包括是否操作被取消了,即時調(diào)用代理方法,根據(jù)配置做不同的操作等等,基本都是邏輯判斷了。最后返回操作對象。
迫不及待要看看平時最常用的UIImageView+WebCache這個分類了,看看頭文件,方法不多,而且功能都很具體,直接看最常用的- (void)sd_setImageWithURL:(NSURL*)url;方法吧。
嗯,只有一句,[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];這個在意料之中的,平時自己封裝工具也經(jīng)常這么干。點進去接著看。
這下進入正菜了。首先取消當(dāng)前的加載任務(wù),因為是ImageView 的分類,一個ImageView自然只需要加載一個image,很好,繼續(xù)。runtime閃亮登場!objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);這個也是runtime里很常用的一個函數(shù),將一個屬性綁定給一個對象。這里將url綁定給了imageView,這樣imageView就有了url這個屬性。接下來處理了一下占位圖和ActivityIndicatorView。然后果然看到了SDWebImageManager的- (id <SDWebImageOperation>)downloadImageWithURL:options:progress:completed:方法。然后就是在完成的回調(diào)里面各種判斷和執(zhí)行完成回調(diào)了。
可以看到,SDWebImage的設(shè)計方式很合理,首先定義基本的管理類來管理這個工具的核心功能——對于SDWebImage就是下載(SDWebImageDownloader)和緩存(SDImageCache)。具體的功能分別在對應(yīng)的類中實現(xiàn)。最后通過分類的形式創(chuàng)建出具體方便的使用方式和場景。一般的工具類都可以借鑒這種設(shè)計方式。
最后附帶一個SDWebImageCompat類的簡介,對于想要公開的代碼庫,兼容性是很重要的問題,而這些內(nèi)容在一般的具體業(yè)務(wù)中很少被考慮到。
#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 的錯誤域,用于輸出錯誤信息。