我們接下來,看 SDWebImage 具體是怎么實現(xiàn)的??梢詠磉@里下載一下源碼注釋
五、詳細的類的解析和該類的流程
根據(jù)方法調(diào)用的流程來看源碼
1.UIImageView+WebCache
使用類別的設計,把設計模式五大原則之一的接口分離原則體現(xiàn)的淋漓盡致。首先說一下什么是接口分離原則:
接口分離原則:為特定功能提供特定的接口,不要使用單一的總接口包括所有功能,而是應該根據(jù)功能把這些接口分割,減少依賴,不能強迫用戶去依賴那些他們不使用的接口。
我們使用的UIImageView+WebCache中提供了多個不同的方法,這樣調(diào)用者需要什么功能就去調(diào)用特定的API,清晰易擴展.
- (void)sd_setImageWithURL:(nullable NSURL *)url
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
而最終該類別中的總接口又調(diào)用了UIView+WebCache中的方法,所以我們下面來看一下UIView+WebCache。
2.UIView+WebCache
問題:
①.為什么要取消加載任務?
②.dispatch_group_t 在這里的作用是什么?
③.setNeedLayout的作用是什么?
我們來看一下sd_internalSetImageWithURL方法里做了哪些事。
- (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
context:(nullable NSDictionary<NSString *, id> *)context
{
1\. 取消當前正在進行的加載任務 operation
2\. 將url作為屬性存起來 set sd_imageURL
3\. 設置 占位圖
4\. 如果 URL 存在,通過url加載圖片,如果url為nil,直接回調(diào) completedBlock
5\. 設置加載到的圖片 ,然后回調(diào) completedBlock
}
流程圖:

image.png
3.SDWebImageManager
問題:
①.SDWebImageCombinedOperation的用途?
②.SDScaledImageForKey的作用?
③.weak-strong dance的用途?
核心類
枚舉
//圖片獲取和設置的選項
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
SDWebImageRetryFailed = 1 << 0,
SDWebImageLowPriority = 1 << 1,
SDWebImageCacheMemoryOnly = 1 << 2,
SDWebImageProgressiveDownload = 1 << 3,
SDWebImageRefreshCached = 1 << 4,
SDWebImageContinueInBackground = 1 << 5,
SDWebImageHandleCookies = 1 << 6,
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
SDWebImageHighPriority = 1 << 8,
SDWebImageDelayPlaceholder = 1 << 9,
SDWebImageTransformAnimatedImage = 1 << 10,
SDWebImageAvoidAutoSetImage = 1 << 11,
SDWebImageScaleDownLargeImages = 1 << 12,
SDWebImageQueryDataWhenInMemory = 1 << 13,
SDWebImageQueryDiskSync = 1 << 14,
SDWebImageFromCacheOnly = 1 << 15,
SDWebImageForceTransition = 1 << 16
};
.h文件中的屬性
@property (weak, nonatomic, nullable) id <SDWebImageManagerDelegate> delegate;
@property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache;
@property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader;
@property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter;
.m文件中的屬性
@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite, nonnull) SDWebImageDownloader *imageDownloader;
//失敗的url數(shù)組
@property (strong, nonatomic, nonnull) NSMutableSet<NSURL *> *failedURLs;
//當前執(zhí)行的任務數(shù)組
@property (strong, nonatomic, nonnull) NSMutableArray<SDWebImageCombinedOperation *> *runningOperations;
.h文件中的方法
+ (nonnull instancetype)sharedManager;
//加載圖片
- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock;
//保存圖片到緩存中
- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url;
//取消當前的operations
- (void)cancelAll;
//檢查operations是否在進行
- (BOOL)isRunning;
//檢查圖片是否存在在緩存里
- (void)cachedImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
- (void)diskImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
//根據(jù)url返回緩存的key
(nullable NSString *)cacheKeyForURL:(nullable NSURL *)url;
.m文件中的方法
//初始化
+ (nonnull instancetype)sharedManager;
- (nonnull instancetype)init
- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader
- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url
//縮放圖片
- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image
//查找圖片
- (void)cachedImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock
- (void)diskImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock
//加載圖片
- (id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock
//緩存圖片
- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url
//operation 相關
- (void)cancelAll
- (BOOL)isRunning
//從runningOperations中移除operation
- (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation
//主線程回調(diào)
- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation
completion:(nullable SDInternalCompletionBlock)completionBlock
error:(nullable NSError *)error
url:(nullable NSURL *)url
- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation
completion:(nullable SDInternalCompletionBlock)completionBlock
image:(nullable UIImage *)image
data:(nullable NSData *)data
error:(nullable NSError *)error
cacheType:(SDImageCacheType)cacheType
finished:(BOOL)finished
url:(nullable NSURL *)url
SDWebImageManager的核心任務是loadImageWithURL方法實現(xiàn)的:
- (id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock
{
1.錯誤檢查
2.創(chuàng)建 SDWebImageCombinedOperation 對象
3.判斷是否是曾經(jīng)下載失敗過的 url
4.如果這個 url 的長度為0,或者曾經(jīng)下載失敗過,并且沒有設置 SDWebImageRetryFailed,就直回調(diào) completedBlock,并且直接返回
5.添加 operation 到 runningOperations 中
6.讀取緩存
6.1如果有緩存就返回 operation
6.2如果沒有就下載圖片,并緩存,然后返回 operation
}
流程圖:

SDWebImageManager.png