SDWebImage源码解读

SDWebImage源码解读

  • 在解读源码前先了解一下 SDWebImage 中几个比较重要的 options(枚举),这有助于我们更好的理解图片的加载的流程:

    1. SDWebImageOptions

      Option 含义
      SDWebImageRetryFailed 一般情况下,一个URL下载失败后会被加入黑名单组织下次下载,如果设置了这个option,则不会加入黑名单
      SDWebImageLowPriority 默认情况下图片会在交互发生时开始下载,设置了这个option图片就会延迟下载,例如滑动 TableView 时,会在 scrollview 减速时才开始下载
      SDWebImageProgressiveLoad 这个option是启用了渐进式下载,像网页加载一样一点一点显示。默认情况下,一次显示完全下载的图片。
      SDWebImageRefreshCached 对缓存进行刷新
      SDWebImageContinueInBackground 后台继续下载
      SDWebImageHandleCookies 通过设置 NSMutableURLRequest.HTTPShouldHandleCookies = YES; 处理 Cookie
      SDWebImageAllowInvalidSSLCertificates 允许使用不受信任的SSL证书,一般用于测试
      SDWebImageHighPriority 默认情况下,图片按照他们加载下载队列中的顺序下载,这个 option 提高下载优先级
      SDWebImageDelayPlaceholder 默认情况下,图片开始加载就显示默认图片,这个 option 延迟了默认图的显示知道图片加载完成
      SDWebImageTransformAnimatedImage 通常情况下我们不会对下载的图片进行变换,因为可能对图片造成损伤,这个 option 可以让我们对图片进行任意变换
      SDWebImageAvoidAutoSetImage 默认情况下,图片在下载后被自动添加到imageView上。这个 option 可以让我们手动添加图片到 imageView 上
      SDWebImageScaleDownLargeImages 当下载的图片太大时,允许把它缩小到一个合适的大小再显示
      SDWebImageQueryMemoryData 默认情况下,当image已经缓存到内存中时,不会再查询imageData,这个 option 可以设置同时查询imageData,这个查询是异步的,除非指定' SDWebImageQueryMemoryDataSync '
      SDWebImageQueryMemoryDataSync 默认情况下,当你只指定' SDWebImageQueryMemoryData '时,会异步查询内存imageData。结合此掩码可以同步查询。但不建议同步查询,除非你想确保图像加载在同一个runloop中,以避免单元格重用时闪烁。
      SDWebImageQueryDiskDataSync 默认情况下,当内存缓存丢失时,异步查询磁盘缓存。该option可以强制同步查询磁盘缓存
      SDWebImageFromCacheOnly 这个 option 可以设置只允许从缓存中获取图片
      SDWebImageFromLoaderOnly 这个 option 可以设置只允许从加载器加载图片
      SDWebImageForceTransition 默认情况下,当你使用“SDWebImageTransition”在图像加载完成后做一些视图转换时,这个转换只适用于从网络下载的图像。这个option可以强制应用内存和磁盘缓存的视图也转换。
      SDWebImageAvoidDecodeImage 默认情况下,我们将在查询缓存或者从网络下载之后直接解码图像。这有助于提高性能,因为在屏幕上呈现图像时,首先需要对其进行解码。但这发生在Core Animation的主队列上。所以,这个进程可能会导致内存使用过大。如果由于内存消耗过多而遇到问题,此option可以阻止对图像进行解码。
      SDWebImageDecodeFirstFrameOnly 默认情况下,会对动图进行解码。这个option强制只解码第一帧并产生静态图像。
      SDWebImagePreloadAllFrames 默认情况下,对于SDAnimatedImage,是在渲染过程中解码动画图像帧以减少内存使用。但是,当动画图像被许多imageViews共享时,可以指定将动图所有帧预加载到内存中,以减少CPU占用。
      SDWebImageMatchAnimatedImageClass 使用这个option,可以确保按照用户提供的类回调相应图像。如果无法生成,则会使用代码“SDWebImageErrorBadImageData”的错误。
      SDWebImageWaitStoreCache 等待图片写入缓存完成再回调
      SDWebImageTransformVectorImage 一般情况下不会对矢量图像做变换,因为矢量图像在做变换时会丢失细节。这个option 可以随意转换矢量图
  • 图片的一次加载主要流程

sequenceDiagram participant 第一步 as some object participant 第二步 as UIImageView (WebCache) participant 第三步 as UIView(WebCache) participant 第四步 as SDWebImageManager participant 第五步 as SDImageCache participant 第六步 as SDWebImageDownloader 第一步 ->> 第二步:1、sd_setImageWithURL: 第二步 ->> 第三步:2、sd_internalSetImageWithURL: 第三步 ->> 第四步:3、loadImageWithURL: 第四步 ->> 第五步:4、queryImageForKey:(queryCacheOperationForKey:) 第五步 -->> 第四步:5、cache result(no image) 第四步 ->> 第六步:6、requestImageWithURL:(downloadImageWithURL:) 第六步 -->> 第四步:7、network result 第四步 ->> 第五步:8、cache image 第四步 -->> 第三步:9、image 第三步 -->> 第二步:10、set image

针对上图中的步骤,我们来一步一步分析:

  1. 首先 SDWebImage 为 UIImagView 创建了一个分类 UIImageView (WebCache),然后 UIImageView 对象可以调用这个分类的方法:- (void)sd_setImageWithURL:(nullable NSURL *)url来下载图片。

  2. UIImageView (WebCache)的- (void)sd_setImageWithURL:(nullable NSURL *)url方法实际调用了UIView (WebCache)的下列方法(UIView (WebCache)是UIView的一个分类):

    - (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;
    
  3. UIView (WebCache) 的上述方法在实现时会创建一个 SDWebImageManager 的实例对象,然后调用其下列方法来加载图片:

    - (id )loadImageWithURL:(nullable NSURL *)url
                                         options:(SDWebImageOptions)options
                                        progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                       completed:(nullable SDInternalCompletionBlock)completedBlock;
    
  4. 在 SDWebImageManager 对象的上述方法里,首先会查询在缓存中有没有这个图片,然后根据各种 option 判断决定是否要从网络端下载。而查询缓存中有没有是通过调用 SDImageCache 对象的实例方法来实现的,SDImageCache 这个类是专门负责缓存相关的问题的,包括查询缓存和将图片进行缓存。SDImageCache 使用了一个 NSCache 对象来进行内存缓存,磁盘缓存则是把图片数据存放在应用沙盒的Caches这个文件夹下,查询方法如下:

    - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key 
                                                options:(SDImageCacheOptions)options 
                                                   done:(nullable SDCacheQueryCompletedBlock)doneBlock;
    
  5. 第4步这里注意,这里的查询缓存的步骤为:首先查询内存缓存,内存缓存查询完了以后再判断是否需要查询磁盘缓存。如果查询内存缓存已经有了结果并且没有设置一定要查询磁盘缓存,那么就不查询磁盘缓存,否则就要查询磁盘缓存。内存缓存没有查询到图片,并且磁盘缓存查询到了图片,那么就要把这个内容缓存到内存缓存中,如果返回缓存查询的结果,如果没有找到,开始第6步下载。

  6. 下载图片,调用 SDWebImageDownloader 对象的下列方法进行下载,SDWebImageDownloader 这个类是专门管理下载的,它有一个属性是 downloadQueue,这是一个NSOperationQueue,每创建一个新的下载任务都把它加入到这个 downloadQueue 中,让 downloadQueue 去管理任务的开始,取消,结束。下载方法:

    - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
                                                       options:(SDWebImageDownloaderOptions)options
                                                      progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                                     completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
    
  7. 获取从网络端下载的图片。

  8. 判断是否要将下载的图片进行缓存,如果需要,则缓存。

  9. 通过 SDWebImageManager 对象获取到图片。

  10. 把图片显示在 UIImageView 上。

原文地址:https://www.cnblogs.com/shisishao/p/15133796.html