版本:5.2.2
SDWebImage时序图
时序图.png
UIImageView/UIButton 调用分类中的设置图片的方法
- (void)sd_setImageWithURL:(nullable NSURL *)url;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder;
...
其提供多个方法设置图片,根据传入的参数可设置图片的占位图、对图片做裁剪等操作。但最终调用的是UIView+WebCache
中的方法
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock
可见该方法传入许多参数,url
对应的是图片远端服务器地址,placeholder
对应的是占位图,可通过options设置图片加载的策略:
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
//失败后重试
SDWebImageRetryFailed = 1 << 0,
//UI交互期间开始下载,导致延迟下载比如UIScrollView减速。
SDWebImageLowPriority = 1 << 1,
//这个标志可以渐进式下载,显示的图像是逐步在下载
SDWebImageProgressiveLoad = 1 << 2,
//刷新缓存,如果设置了该类型,缓存策略依据NSURLCache而不是SDImageCache,所以可以通过NSURLCache进行缓存了
SDWebImageRefreshCached = 1 << 3,
//后台下载
SDWebImageContinueInBackground = 1 << 4,
SDWebImageHandleCookies = 1 << 5,
//允许使用无效的SSL证书
SDWebImageAllowInvalidSSLCertificates = 1 << 6,
//优先下载
SDWebImageHighPriority = 1 << 7,
//延迟占位符
SDWebImageDelayPlaceholder = 1 << 8,
//改变动画形象
SDWebImageTransformAnimatedImage = 1 << 9,
//手动在图片下载完成后设置图片
SDWebImageAvoidAutoSetImage = 1 << 10,
SDWebImageScaleDownLargeImages = 1 << 11,
//查询内存缓存
SDWebImageQueryMemoryData = 1 << 12,
//同步查询内存缓存
SDWebImageQueryMemoryDataSync = 1 << 13,
//同步查询磁盘缓存
SDWebImageQueryDiskDataSync = 1 << 14,
SDWebImageFromCacheOnly = 1 << 15,
SDWebImageForceTransition = 1 << 17,
SDWebImageAvoidDecodeImage = 1 << 18,
SDWebImageDecodeFirstFrameOnly = 1 << 19,
SDWebImagePreloadAllFrames = 1 << 20,
SDWebImageMatchAnimatedImageClass = 1 << 21,
}
context
字段是一个字典类型,主要是可传入各种处理器,如控制图片裁剪、缩放的转换器,自定义缓存key生成规则的过滤器,还有对图片做变换的处理器,见下所示字段,其中imageTransformer
为图片转换器,cacheKeyFilter
可自定义缓存key规则,cacheSerializer
则是图片格式等转换器。这3个生成器都是协议,因此只需要传入对应的实现协议的类对象即可。
SDWebImageContextOption const SDWebImageContextSetImageOperationKey = @"setImageOperationKey";
SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager";
SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransformer";
SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor";
SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType";
SDWebImageContextOption const SDWebImageContextOriginalStoreCacheType = @"originalStoreCacheType";
SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass";
SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier";
SDWebImageContextOption const SDWebImageContextCacheKeyFilter = @"cacheKeyFilter";
SDWebImageContextOption const SDWebImageContextCacheSerializer = @"cacheSerializer";
setImageBlock
可不用关系,在调用UIView分类中的方法时默认传入的未nil
至于progressBlock
则是进度回调,可在该回调中去实现图片加载的进度显示
completedBlock
是在图片加载完成(缓存加载、图片下载都视为图片加载完成)的回调,在特殊业务下可在该回调中去进行布局等操作。
在方法内部,首先回去取消掉上一次的的下载操作,避免为同一张图片添加多个opreation进行下载操作
//取消当前下载operation
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
对用户显示图片的策略进行处理,其在内部又会去判断客户端以及视图类型(UIImageView、UIButton),但最终还是会显示用户传入的placeholder
//如果是非延迟显示占位图,也就是默认在图片加载开始的时候就显示占位图
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url];
});
}
最终会去调用SDWebImageManager
中的图片加载方法,传入的参数基本与UIView+WebCache
中的方法一致
- (SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock
判断当前的url
是否在黑名单中,因为在后续的下载操作中,如果该图片资源在远端服务器上有问题,那么会默认该url存在异常,就会加入的黑名单中,避免每次对资源损伤的url
去做下载操作浪费资源
BOOL isFailedUrl = NO;
if (url) {
SD_LOCK(self.failedURLsLock);
isFailedUrl = [self.failedURLs containsObject:url];
SD_UNLOCK(self.failedURLsLock);
}
再根据策略判断是否需要从缓存中查询图片资源,如果需要那么会先去查询内存,如果内存中存在图片资源那么直接返回图片资源,如果不存在那么那么根据策略判断是否需要前往磁盘查询图片资源,如果找到资源那么返回图片资源。
根据从缓存中查询的结果再根据图片加载的策略判断是否需要再去从服务器上下载图片资源。因为如果策略为SDWebImageRefreshCached
那么表示需要刷新缓存数据,此时即便从缓存中查找到了图片资源仍然需要从服务端下载最新的图片资源,不过在此种情况下会先将缓存中的图片资源显示在去下载。
下载核心则是在调用SDWebImageDownloader
的方法
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock
根据图片的加载策略配置下载的operation
operation = [self createDownloaderOperationWithUrl:url options:options context:context];
然后将其加入到对应的下载队列downloadQueue
中,同时也会将其加入到自定义的URLOperations
集合中进行管理。
self.URLOperations[url] = operation;
// Add operation to operation queue only after all configuration done according to Apple's doc.
// `addOperation:` does not synchronously execute the `operation.completionBlock` so this will not cause deadlock.
[self.downloadQueue addOperation:operation];
注意在将operation
加入到队列的时候也会启动下载操作。因为SDWebImageDownloaderOperation
是继承NSOperation
的,作者重写了其start
方法,所以下载的业务的处理都是在SDWebImageDownloaderOperation
中的
作者通过NSURLSession去进行下载业务,在对应的回调方法中回去图片资源以及业务处理
#pragma mark NSURLSessionDataDelegate
//处理整个请求结束的业务逻辑,判断图片是否下载成功,是否是损坏资源
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
//接收图片资源,并组装为图片显示,如果用户设置了图片加载策略为渐进式加载那么在这里会将下载好的部分资源重绘为一张图片返回显示
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
//使用NSURLCache
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
#pragma mark NSURLSessionTaskDelegate
//下载失败的结果处理
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
//校验业务的处理
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
最终将结果回调给UIView+WebCache
的completedBlock
中。至此整个图片加载流程大致如上。其中涉及到图片的解压缩方面没有提及,还有代码中许多细节的实现也是需要理解,所以后续仍需要保持阅读源码。
网友评论