美文网首页
SDWebImage源码分析

SDWebImage源码分析

作者: oldmonster | 来源:发表于2019-11-22 15:11 被阅读0次

版本: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+WebCachecompletedBlock中。至此整个图片加载流程大致如上。其中涉及到图片的解压缩方面没有提及,还有代码中许多细节的实现也是需要理解,所以后续仍需要保持阅读源码。

相关文章

  • SDWebImage 源码分析

    SDWebImage 源码分析 首先我 fork 了 SDWebImage 的源码,见 conintet/SDWe...

  • SDWebImage源码分析

    SDWebImage源码分析 UIImageView+WebCache sd SDWebImageManager ...

  • SDWebImage源码分析

    技术无极限,从菜鸟开始,从源码开始。 由于公司目前项目还是用OC写的项目,没有升级swift 所以暂时SDWebI...

  • SDWebImage源码分析

    SDWebImage介绍 UIView+WebCache类别: 所有设置图片的方法内部都会且仅调用此方法 UIVi...

  • SDWebImage源码分析

    SDWebImage是专门用于图片下载的框架,内部封装了图片异步下载和缓存的过程,涉及到的知识点有:(1)runt...

  • SDWebImage源码分析

    SDWebImage库是一个支持缓存的异步图片下载库。为了方便使用,它提供了UIImageView, UIButt...

  • SDWebImage源码分析

    一、SDWebImage到底是什么 Asynchronous image downloader with cach...

  • SDWebImage源码分析

    使用SDWebImage无非就是做图片缓存 一起来看下SDWebImage的几种使用方式:SDWebImage下载...

  • 源码分析SDWebImage

    SDWebImage是一个开源的第三方库,它提供了UIImageView的一个分类,以支持从远程服务器下载并缓存图...

  • 源码分析SDWebImage

    /* *ThisfileispartoftheSDWebImagepackage. *(c)OlivierPoit...

网友评论

      本文标题:SDWebImage源码分析

      本文链接:https://www.haomeiwen.com/subject/rljjictx.html