SDWebImage
庫總體分為這么幾個部分:
- 類似
UIImageView+WebCache
這樣的面向使用者的接口,由各個分類的sd_setImageWithURL:...
系列方法組成,是我們最常接觸使用的部分。 -
SDImageCache
,是SDWebImage
庫中負責緩存工作的類。 -
SDImageDownloader
,是SDWebImage
庫中負責下載工作的類。 -
SDWebImageManager
,是管理SDImageCache
和SDImageDownloader
,讓它們協同工作的類。在各個分類的背后默默工作。
UIView+WebCacheOperation
這個分類中提供了幾個方法,可以對operation進行操作。
首先這個分類中,使用Runtime
為UIView
添加一個字典屬性(NSMutableDictionary<NSString *, id>
),里面存儲了一些下載操作id <SDWebImageOperation> operation
,可能為一個op或者op集合。
刪除operation
- (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key
查找字典中以key
為鍵的op,并刪除。
取消operation
- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key
查找字典中以key
為鍵的op,調用- (void)cancel
方法。(如果是集合,則遍歷調用cancel
)。取消后會將op從字典中刪除。
添加operation
- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key
先取消key
對應的op,再將新想op添加到字典中。
UIView+WebCache
這個分類中提供了圖片下載、設置的方法,為這個庫中UIImageView
分類和UIButton
分類的sd_set...
系列方法提供支持。還提供了顯示/隱藏ActivityIndicator
的方法。
- (nullable NSURL *)sd_imageURL;
獲取當前視圖圖片的url,方法通過Runtime
獲取,因此如果我們在設置圖片時直接使用setImage
而非使用sd中的方法,會使這個方法獲取的值錯誤。
// 取消當前視圖的圖片下載
- (void)sd_cancelCurrentImageLoad
上面這個方法會以類名為key,調用UIView+WebCacheOperation
中的- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key
方法來取消圖片下載操作。
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock {
if (setImageBlock) {
setImageBlock(image, imageData);
return;
}
#if SD_UIKIT || SD_MAC
if ([self isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = (UIImageView *)self;
imageView.image = image;
}
#endif
#if SD_UIKIT
if ([self isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)self;
[button setImage:image forState:UIControlStateNormal];
}
#endif
}
內部方法設置圖片,如果有setImageBlock則調用它來設置圖片,否則的話UIImageView
調用setImage:
方法,UIButton
調用setImage:forState:
方法來設置圖片。
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
operationKey:(nullable NSString *)operationKey
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
這個方法是這個分類的核心方法,也是UIImageView+WebCache
和UIButton+WebCache
中各個方法設置圖片時實際調用的方法。
這個方法中做的主要事情是調用SDWebImageManager
中的方法創建一個operation,并將這個op添加到op字典中。
方法中會在創建operation前使用上面內部方法設置placeholder圖片,如果設置了SDWebImageDelayPlaceholder
,則會跳過,最后在operation回調中,如果下載圖片失敗再設置placeholder。
方法中對op的complete回調進行了處理,如果設置了SDWebImageAvoidAutoSetImage
,會直接調用completeBlock
,否則的話會使用下載的圖片或者占位圖作為參數,調用setImageBlock
, 最后調用completeBlock
。
這兩個block的調用都是通過調用上面提到的內部方法sd_setImage:imageData:basedOnClassOrViaCustomSetImageBlock:
。
實際在UIImageView+WebCache
中調用這個方法時,setImageBlock
是nil,除非調用的是帶completeBlock
的方法并設置了block值,否則completBlock
也會傳入nil,最終將使用imageView.image = image
這樣的方法設置圖片,而不是由外部block設置。
UIButton+WebCache
中調用時,setImageBlock
會有值,其內容是調用UIButton
的setImage:forState:
或者setBackgroundImage:forState:
方法。completBlock
除非設置否則為空。
UIImageView+WebCache
這個分類中提供了一系列sd_setImage...
方法供外部調用,是使用者最經常接觸的API,這系列方法最終都是調用到了UIView+WebCache
中的核心方法。
另外,UIImageView
是支持多圖動畫的,這個分類也提供了相應的方法:
- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs {
[self sd_cancelCurrentAnimationImagesLoad];
__weak __typeof(self)wself = self;
NSMutableArray<id<SDWebImageOperation>> *operationsArray = [[NSMutableArray alloc] init];
for (NSURL *logoImageURL in arrayOfURLs) {
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_async_safe(^{
__strong UIImageView *sself = wself;
[sself stopAnimating];
if (sself && image) {
NSMutableArray<UIImage *> *currentImages = [[sself animationImages] mutableCopy];
if (!currentImages) {
currentImages = [[NSMutableArray alloc] init];
}
[currentImages addObject:image];
sself.animationImages = currentImages;
[sself setNeedsLayout];
}
[sself startAnimating];
});
}];
[operationsArray addObject:operation];
}
[self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"];
}
- (void)sd_cancelCurrentAnimationImagesLoad {
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"];
}
使用多個url來創建多個operation,再將這些op放入數組,最后將op數組添加到op字典中。添加op和取消下載都單獨提供了一個key與正常的一張圖片的操作區分。
UIImageView+HighlightedWebCache
與此分類類似,唯一不同的是,它會提供核心方法參數中的setImageBlock
,其內容就是設置highlightedImage
。
UIButton+HighlightedWebCache
與此分類類似,唯一不同的是,它會提供核心方法參數中的setImageBlock
,其內容就是設置setImage:forState:
或者setBackgroundImage:forState:
。
UIImage+GIF
使用NSData創建Gif圖片
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data
判斷是否是Gif
- (BOOL)isGIF {
return (self.images != nil);
}
SDWebImagePrefetcher
預加載圖片,默認在主隊列,低優先級加載圖片。
可以通過prefetcherQueue
、options
、maxConcurrentDownloads
等對預加載進行控制,可以通過代理的回調獲取預加載的狀態信息。
SDWebImageOperation
一個協議,里面只定義了一個取消方法。
@protocol SDWebImageOperation <NSObject>
- (void)cancel;
@end
SDImageCacheConfig
圖片緩存設置
- shouldDecompressImages,是否解碼圖片。對下載和緩存的圖片解碼,可以加快圖片的顯示,但會消耗更多的內存。默認YES。
- shouldDisableiCloud,是否禁用iCloud備份,默認YES,即禁用。
SharedSDImageCache
默認存儲的沙盒路徑(Cache)是不會被iCloud備份的,但是SDImageCache可以添加自定義緩存路徑,這時候就可能存儲在會被iCloud備份的路徑上,此時這個選項就有了意義。 - shouldCacheImagesInMemory,是否在內存中緩存圖片,默認YES。
- maxCacheAge,最大緩存時間(秒為單位),默認一周。
- maxCacheSize,最大緩存空間(bytes),默認0。
SDImageCache
SDImageCache
圖片緩存,它包括內存緩存和可選的硬盤緩存,硬盤緩存寫入時是異步的,不會阻塞UI。
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns
diskCacheDirectory:(nonnull NSString *)directory
初始化,SD會在沙盒的Cache文件夾下創建命名空間同名的文件夾A,最終以/Sandbox/Library/Caches/namespace/com.hackemist.SDWebImageCache.namespace
作為硬盤緩存路徑。
初始化時會注冊通知,在程序收到內存警告時清除所有內存緩存,在即將關閉和進入后臺時清除過期硬盤緩存。刪除過期文件方法中,會優先刪除過期文件(默認為保存一周)。
過期文件刪除之后計算緩存大小,如果大小超過設置的緩存大小限制,會繼續刪除,優先刪除最舊的圖片,刪到緩存大小為設置大小一半為止。
會創建一個自定義串行隊列做IO操作,所有的存入、刪除、查詢操作都會在這個隊列里完成,以此來保證線程安全。獲取圖片并沒有控制在此隊列完成。
sharedImageCache
單例會以default
為命名空間初始化。
內部的AutoPurgeCache
, 繼承自NSCache
,在收到內存警告時,會自動刪除內存中的所有緩存。SD中的內存緩存屬性為NSCache
,實際為使用AutoPurgeCache
初始化的實例。
NSUInteger SDCacheCostForImage(UIImage *image)
, 計算一張圖片的緩存大小消耗。在Mac中為wid * hei
, 在iOS中為wid * scale * hei * scale
。
- (void)addReadOnlyCachePath:(nonnull NSString *)path
添加硬盤緩存的搜索路徑,可以在想預加載Bundle資源時使用。
- (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key
以key獲取硬盤緩存文件的文件名,文件名是將key做MD5加密,如果后后綴名加上文件后綴。
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
根據參數和配置(SDImageCacheConfig
)將圖片緩存到內存和硬盤。
緩存到硬盤時,會控制在初始化時創建的io隊列進行操作,實際調用了
- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key
這個方法進行存儲,這個方法中會檢查隊列是否是指定的io隊列,不會再控制代碼在io隊列上執行。
如果方法沒提供imageData
,會將image轉為Data, 最后存入硬盤的是Data。
如果設置中包含了禁用iCloud備份,會在存入時對URL設置禁用iCloud備份。
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock
以key獲取文件路徑,查詢硬盤圖片是否存在,并不會加載圖片。
- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key {
return [self.memCache objectForKey:key];
}
以key查找內存緩存的圖片。
- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key {
UIImage *diskImage = [self diskImageForKey:key];
if (diskImage && self.config.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost];
}
return diskImage;
}
// inner method
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key {
// 查找硬盤緩存Data
NSData *data = [self diskImageDataBySearchingAllPathsForKey:key];
if (data) {
UIImage *image = [UIImage sd_imageWithData:data];
// 如果文件名包含@2x、@3x,會以不同的scale創建UIImage
image = [self scaledImageForKey:key image:image];
if (self.config.shouldDecompressImages) {
// 解碼圖片
image = [UIImage decodedImageWithImage:image];
}
return image;
}
else {
return nil;
}
}
獲取硬盤緩存的圖片,查找的時候會從所有的路徑查找(默認路徑+自定義路徑),查找到Data后會根據圖片種類創建不同的UIImage對象([UIImage sd_imageWithData:]
), 比如Gif、WebP等,并根據文件名是否包含@2x、@3x調整image的scale。
如果設置了預解碼,會對圖片進行解碼,解碼操作會過濾調動圖和含有alpha通道的圖片。
如果設置了內存緩存,會將圖片添加到內存緩存中。
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key
查找緩存的圖片,先從內存查找,沒有再從硬盤查找。
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key
done:(nullable SDCacheQueryCompletedBlock)doneBlock
返回一個[NSOperation new]
, 方法會先查找內存緩存,如果找到則以對應的圖片、Data、緩存類型等調用done
回調。如果沒找到會在io隊列查找硬盤緩存。
如果所返回的NSOperation
被取消,則會停止查找硬盤緩存。
- (void)removeImageForKey:(nullable NSString *)key
fromDisk:(BOOL)fromDisk
withCompletion:(nullable SDWebImageNoParamsBlock)completion
從緩存中刪除圖片。
如果設置了內存緩存,則會從內存緩存中刪除圖片。
如果fromDisk
為真,則會在io隊列中刪除硬盤緩存。
回調會在主線程被調用。
- (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock
刪除過期文件方法中,會優先刪除過期文件(默認為保存一周)。
過期文件刪除之后計算緩存大小,如果大小超過設置的緩存大小限制,會繼續刪除,優先刪除最舊的圖片,刪到緩存大小為設置大小一半為止。
SDWebImageDownloaderOperation
SDWebImageDownloaderOperation
繼承自NSOperation
,實現了多個代理協議方法:
-
SDWebImageDownloaderOperationInterface
, 提供創建對象方法;添加下載過程回調、結果回調;設置是否解碼圖片等。 -
SDWebImageOperation
,提供- (void)cancel
方法。 -
NSURLSessionTaskDelegate
和NSURLSessionDataDelegate
這個類是下載圖片的operation對象,它會處理NSURLSessionTaskDelegate
和NSURLSessionDataDelegate
中的方法。
這個類內部有兩個NSURLSession
類型屬性:
-
unownedSession
,外部提供的session,由外部管理和負責置空,代理和代理方法也由外部控制實現。 -
ownedSession
,當外部提供的session為空時,內部創建的session,自己負責停用和置空,自己實現代理方法。
SD實際代碼中,外部session由SDWebImageDownloader
提供和管理,Downloader中實現了相關代理方法,但是在代理方法中會調用SDWebImageDownloaderOperation
實現的相關代理方法來處理邏輯:
// SDWebImageDownloader中
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
// 調用operation實現的代理方法
[dataOperation URLSession:session task:task didCompleteWithError:error];
}
這個類內部維護了一個回調字典,存儲了所有添加的progressCallback
和completedCallback
,并創建了一個barrierQueue
,將對回調字典的操作放到這個隊列中來保證線程安全。
類里面重寫了NSOperation
的- (void)start
和- (void)cancel
方法,結合下載的各個代理方法控制operation的finished
和executing
狀態, 并根據NSOperation的文檔重寫了這兩個屬性的setter
。
@property (readonly, getter=isExecuting) BOOL executing
A Boolean value indicating whether the operation is currently executing.
The value of this property is YES if the operation is currently executing its main task or NO if it is not.
When implementing a concurrent operation object, you must override the implementation of this property so that you can return the execution state of your operation.
In your custom implementation, you must generate KVO notifications for the isExecuting
key path whenever the execution state of your operation object changes. For more information about manually generating KVO notifications, see Key-Value Observing Programming Guide.
You do not need to reimplement this property for nonconcurrent operations.
finished
與之相同。
如果實現的operation是并發的,必須重寫這兩個屬性,來自己控制op的狀態,并且需要在屬性改變時給出KVO通知。如果不是并發的,則沒必要重寫。
@implementation SDWebImageDownloaderOperation {
@synthesize executing = _executing;
@synthesize finished = _finished;
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
- (void)setExecuting:(BOOL)executing {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
}
重寫父類屬性時,需要使用到成員變量,則要用@synthesize
,否則在子類重寫的setter
和getter
中是訪問不到的。
SDWebImageDownloader
SD中的圖片下載器,與SDWebImageCache
構成這個庫中的“下載”和“緩存”兩大核心。
下載選項
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
// 默認,影響下載操作在隊列中的優先級
SDWebImageDownloaderLowPriority = 1 << 0,
// 漸進式下載,可以逐步顯示出圖片全部
SDWebImageDownloaderProgressiveDownload = 1 << 1,
/**
* 默認情況下下載圖片請求會設置NSURLRequestReloadIgnoringLocalCacheData緩存策略,不使用NSURLCache緩存。
* 如果設置了這個選項,會使用NSURLRequestUseProtocolCachePolicy,啟動NSURLCache緩存。
*/
SDWebImageDownloaderUseNSURLCache = 1 << 2,
/**
* 忽略從NSURLCache緩存的圖片,如果圖片是從NSURLCache獲取到,則以nil來回調
* 可以結合`SDWebImageDownloaderUseNSURLCache`一起使用。
*/
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
// 在App進入后臺繼續下載圖片
SDWebImageDownloaderContinueInBackground = 1 << 4,
// 影響NSMutableURLRequest.HTTPShouldHandleCookies屬性值
SDWebImageDownloaderHandleCookies = 1 << 5,
// 允許不被信任的SSL證書
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,
// 高優先級下載圖片
SDWebImageDownloaderHighPriority = 1 << 7,
// 默認情況下,硬盤緩存的Data是在請求中逐漸拼接起來的NSMutableData
// 如果設置此項,則使用UIImagePNGRepresentation(image), 此Data會比前者更小
SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
};
下載順序
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
// 默認值,先進先出
SDWebImageDownloaderFIFOExecutionOrder,
// 后進先出
SDWebImageDownloaderLIFOExecutionOrder
};
屬性初始化
-
shouldDecompressImages
, 是否解碼圖片,默認YES。 -
executionOrder
, 隊列順序,默認先進先出。 -
maxConcurrentOperationCount
,隊列最大任務并發數,默認6個。 -
downloadTimeout
,任務超時時間,默認15秒。
另外,會創建一個NSURLSession
用來進行請求,注意,不是使用sharedSession
,而是單獨創建一個session。在Downloader對象銷毀時會調用session的- (void)invalidateAndCancel
方法并置空。
另外還會會維護一個URLOperations
字段來存儲所有的operation,這個字典的操作會放在一個自營第隊列中,來保證線程安全。
下載圖片
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock
使用URL創建請求request,根據options參數設置request的緩存策略(是否使用NSURLCache
緩存)、設置cookie處理方式、設置請求頭等。
如果URL對應的SDWebImageDownloaderOperation
不存在于內部字典中,則會以request創建一個op,根據options參數設置op的優先級,并添加到隊列中。如果隊列的執行順序是后進先出,則將之前的最后一個op添加依賴到新的op上來確保執行順序。
方法會返回一個Token
,可以用來取消對應的op。
SDWebImageCombinedOperation
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic, nullable) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic, nullable) NSOperation *cacheOperation;
@end
@implementation SDWebImageCombinedOperation
- (void)setCancelBlock:(nullable SDWebImageNoParamsBlock)cancelBlock {
// check if the operation is already cancelled, then we just call the cancelBlock
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
} else {
_cancelBlock = [cancelBlock copy];
}
}
- (void)cancel {
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock) {
self.cancelBlock();
// TODO: this is a temporary fix to #809.
// Until we can figure the exact cause of the crash, going with the ivar instead of the setter
// self.cancelBlock = nil;
_cancelBlock = nil;
}
}
這個類遵守SDWebImageOperation
協議,實現了- (void)cancel
方法,并且有一個NSOperation
類型的cacheOperation
屬性和一個cancelBlock
屬性。
在- (void)cancel
方法中,cacheOperation
的取消方法會被調用,然后調用cencelBlock
。
SDWebImageManager
SD中的核心類,由它來協調SDImageCache
和SDWebImageDownloader
協同工作。
下載選項:
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
// 下載失敗過的URL會從黑名單中刪除并重新嘗試下載
SDWebImageRetryFailed = 1 << 0,
// 對應SDWebImageDownloaderLowPriority,低優先級的下載任務不會在UI交互時啟動
SDWebImageLowPriority = 1 << 1,
// 只進行內存緩存
SDWebImageCacheMemoryOnly = 1 << 2,
// 對應SDWebImageDownloaderProgressiveDownload,漸進式下載顯示
SDWebImageProgressiveDownload = 1 << 3,
/**
* 對應SDWebImageDownloaderUseNSURLCache
* 即使圖片有SD緩存,也會遵循HTTP的緩存控制,在需要的時候從遠端獲取圖片,比如遠端圖片有新版本。本地硬盤緩存會由NSURLCache進行處理,而不是SDWebImage。
* 這個在同一個URL對應的圖片可能發生改變時很有用,比如一個頭像圖片的URL。
* 如果緩存圖片被刷新了,回調會先被調用一次,參數是緩存圖片,然后用請求的圖片作為參數再調用一次。
*/
SDWebImageRefreshCached = 1 << 4,
// 對應SDWebImageDownloaderContinueInBackground,App進入后臺時繼續下載圖片,如果后臺任務超時,任務會被取消。
SDWebImageContinueInBackground = 1 << 5,
/**
* 對應SDWebImageDownloaderHandleCookies,會設置
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
* 來處理存儲在NSHTTPCookieStore中的cookie
*/
SDWebImageHandleCookies = 1 << 6, 會設置
// 對應SDWebImageDownloaderAllowInvalidSSLCertificates,允許不受信任的SSL證書
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
// 對應SDWebImageDownloaderHighPriority,高優先級任務會在下載隊列中被優先下載
SDWebImageHighPriority = 1 << 8,
// 延遲占位圖展示,默認占位圖會在下載圖片前顯示,使用此項后,占位圖會在下載任務完成后沒有圖片的情況下才顯示
SDWebImageDelayPlaceholder = 1 << 9,
/** 默認SDWebImageManager是不會調用下面的代理方法預處理下載好的動圖的:
* imageManager:transformDownloadedImage:withURL:
* 使用這個選項,manager在下載完成后、緩存圖片和回調前會調用此代理方法獲取處理過的圖片
*/
SDWebImageTransformAnimatedImage = 1 << 10,
// 默認會自動將圖片設置到視圖上,使用此項取消自動設置
SDWebImageAvoidAutoSetImage = 1 << 11,
// 對應SDWebImageDownloaderScaleDownLargeImages,如果設置了`SDWebImageProgressiveDownload`,則此項會失效
SDWebImageScaleDownLargeImages = 1 << 12
};
協議方法
@class SDWebImageManager;
@protocol SDWebImageManagerDelegate <NSObject>
@optional
// 控制圖片是否應該下載
- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL;
// 在圖片下載后、緩存圖片前調用此方法處理圖片,方法會在全局隊列中調用
- (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL;
@end
- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url;
@property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
cacheKeyForURL:
返回URL對應的緩存key,如果有cacheKeyFilter
會使用它的返回值作為最終的值,否則返回url.absoluteString
。
- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock;
如果URL對應的圖片不在緩存中,則進行下載。
方法會創建并返回一個SDWebImageCombinedOperation
類型的operation,operation的cacheOperation
是由[self.imageCache queryCacheOperationForKey:...]
方法返回的一個NSoperation
。
如果需要下載圖片,則會調用[self.imageDownloader downloadImageWithURL:...]
方法下載圖片,方法返回一個SDWebImageDownloadToken
類型的token,這個token會被前面的operation的cancelBlock
捕獲,在block中使用這個token來調用[self.imageDownloader cancel:token]
方法進行取消。
- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url
將圖片緩存到內存和硬盤。
- (void)cachedImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
異步確認url對應的圖片是否存在于緩存中,先從內存查找,否則異步在硬盤查找,回調在主線程執行。
- (void)diskImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
異步確認URL對應的圖片是否存在于硬盤緩存, 不會加載圖片,回調在主線程執行。
各個Operation
之間的關系
在上面的各個類中,可以看到有好幾種Operation
,和取消方法。總結如下:
NSOperation
1. - (void)cencel;
SDWebImageOperation協議
1. - (void)cancel;
SDImageCache:
`queryCacheOperationForKey:...`方法
1. query操作首先查找內存, 命中則回調,返回nil
2. 返回NSOperation,異步查找硬盤,回調。
SDWebImageDownloaderOperation:
1. 內部維護callbackBlocks數組,數組元素為Dic<KEY,BLOCK>
2. `- (void)cancel`,調用父類NSOperation的cancel方法,調用dataTask的cancel方法,設置狀態
3. `- (BOOL)cancel:(nullable id)token`,從內部維護的callbackBlocks數組中刪除對應的回調,調用`- (void)cancel`方法
SDWebImageDownloader:
1. 內部維護URLOperations字典,key為URL,值為SDWebImageDownloaderOperation
2. `- (void)cancel:(nullable SDWebImageDownloadToken *)token`,
使用token.URL從URLOperations字典中獲取downloaderOp, 調用downloaderOp的
`- (BOOL)cancel:(nullable id)token`方法。將downloaderOp從字典中刪除。
3. `downloadImageWithURL:..`方法返回SDWebImageDownloadToken,
方法內會創建SDWebImageDownloaderOperation,將downloaderOp添加到URLOperations字典中,將downloaderOp添加到隊列中。
4. `- (void)cancelAllDownloads`,方法會調用`[self.downloadQueue cancelAllOperations]`,系統會對隊列內的所有operation調用`- (void)cancel`方法。
SDWebImageCombinedOperation:
1. 遵守SDWebImageOperation協議
2. 有一個NSOperation類型cacheOperation屬性
3. 有一個cancelBlock屬性
4. `- (void)cancel`方法內會調用cancelBlock和cacheOperation的cancel方法
SDWebImageManager
1. 內部維護一個runningOperations數組,里面的對象是SDWebImageCombinedOperation
2. `loadImageWithURL:..`,會創建`SDWebImageCombinedOperation`類型的combinedOp,
創建combinedOp.cacheOperation為`[SDImageCache.sharedCache queryCacheOperationForKey:...]`的返回值,
如果沒有查找到緩存圖片,則下載。下載會調用`[SDWebImageDownloader.sharedDownloader downloadImageWithURL:...]`方法,
返回的SDWebImageDownloadToken被combinedOp的cancelBlock捕獲。
3. 在queryCache或者downloadImage的過程中,如果combinedOp被cancel,則會被從runningOperations中刪除。