SDWebImage 源码阅读 (一)
前言
SDWebImage 这个库是 OC 中最流行的网络图片加载库,它实现了图片下载,缓存,更新等和加载网络图片相关的绝大多数事情。如果项目的图片加载方面没有奇怪需求的话,这个库一定能够胜任的。之前只是粗略的看了一下这个库的实现逻辑,没有细看,今天来重新看一下。
由于本人是流程图菜鸟,并且本库使用了大量的 block,所以我打算使用分步拆解的方式来画流程图,并且我会把Block单独拿出来画一下流程图,虽然看起来会比较乱,但是好画啊。如果一个流程图示包含在其他流程图中的话,我会用颜色标出来。下面先来一个大致的总流程图:
大致流程
在调用加载网络图片的方法后,都会调用到 UIView+WebCache.h 67
的 sd_internalSetImageWithURL:
方法。后面的步骤大致如下:
- 获取 operationKey 并取消当前关于这个 Key 的 operation
- 如果需要则显示设置占位图
- 重置和创建一些值、Block
- 查找缓存(先内存,再磁盘)
- 设置图片并开始下载图片(下载的原因有可能是需要更新缓存或者没有命中缓存)
- 设置图片并把下载的图片缓存到本地磁盘和内存中
步骤分解
loadImageWithURL
这个是加载过程中最重要的步骤,主要是判断URL是否有效并查找缓存。
loadImageWithURL.png
callCompletionBlockForOperation
这个步骤其实就是在创建和调用 operation 过程中会出现需要直接返回的情况(出现错误,流程结束等), 直接调用这方法来快捷的调用 completionBlock 。内部实现就是把 Block 的调用放在一个安全的GCD里面,具体内部逻辑就是判断当前线程是否为主线程:
- 如果是主线程,则直接调用 block,
- 如果不是主线程,则使用
dispatch_async(dispatch_get_main_queue(), block);
调用 block
combinedProgressBlock
这是一个处理下载进度的 Block。这个Block在图片下载过程中会被调用到,自定义图片进度方法sd_imageProgress
、图片指示器id<SDWebImageIndicator>
和下载进度progressBlock
会被分别调用到。
loadImageOperationBlock
这个是检查并加载本地图片资源并发起网络请求后调用的一个Block,重置imageProgress
、ImageIndicator
。
这里会定义一个结束之后的 block callCompletedBlockClojure
,这个 Block 会判断是否需要刷新页面,不需要的话则不会调用sd_setNeedsLayout
方法。并且决定是否要调用完成的block(completedBlock
)。
定义完 block 会判断一下,如果不需要设置图片的话直接调用这个 block,如果需要设置图片则会根据传入的图片信息来调用 sd_setImage:
方法来设置图片,最后调用这个内部的 block 来结束。
sd_setImage
这个会根据当前不同的View来调用不同的设置图片的方法,设置完之后会执行:
- 如果有显示动画的要求的话,也会调用相关的动画代码,并在完成后调用传入的 Block
-
如果没有显示动画的要求,则直接调用传入的 Block
sd_setImage.png
cacheOperationBlock
这个 Block 是在调用缓存方法之后的返回Block,里面主要处理获取缓存的结果和调用下载方法。
cacheOperationBlock.png
download & downloadBlock
这个 Block 是图片下载完成后调用的Block,图片下载部分本篇文章就不展开了,这部分其实有很多可以实现方式,本库中是使用原生的 NSURLSession 方式调用的。我们自己写的话也可以用这种方式,或者使用第三方库。以后有时间我在单独看看 NSURLSession 相关的东西。
callDownloadProcessForOperation.png
最后
这个库里面除了关于图片流程相关的这些以外,关于多平台(OSX、iPhone(iPad)、WatchOS)的适配方式其实是值得借鉴的,如果想要做一个比较稳健的通用型开源库,平台适配和判断一定是必选项。
这就是我看到的关于 SDWebImage 这个库加载图片的流程了,一定会有什么遗漏的地方,欢迎斧正。