2019-01-09SDW0

最新源码更新:

SD外部API没变,但是内部的封装和逻辑有一些小小的改变,最近把YYKit也全部分析了一遍,由于之前也看过SD,回头一看已经变了,再分析一遍最新的

笔记:

validOperationKey --- > [self class]
SDOperationDictionary ---> 通过Category Runtime 挂载到UIView控件

内部存储 SDWebImageCombinedOperation ( 这里有个 cacheOperation 用来存储缓存的操作 )

最新调用顺序

  1. 通用方法
 - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder
  1. SDWebImageManager 单例调用
- (nullable id )loadImageWithURL:(nullable NSURL *)url
                                              options:(SDWebImageOptions)options
                                             progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                            completed:(nullable SDInternalCompletionBlock)completedBlock;

SDWebImageManager 的两个单例

@property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache; // 处理缓存
@property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader; // 处理网络下载

SDWebImageManager上面那个方法下面初始化

__block SDWebImageCombinedOperation *operation = 
[SDWebImageCombinedOperation new]; 
operation.manager = self; // .manager的类型就是 SDWebImageManager
  • SDImageCache =====> 缓存单例
// 二级缓存查找方法,把队列返回赋值给Operation的Cache字段
operation.cacheOperation = [self.imageCache queryCacheOperationForKey。。。] 

内存缓存 NSCache 磁盘缓存 FileManager文件存储 无论查找与否都返回,只是image是否为空的区别

  • SDWebImageDownloader ======>下载单例
    (URLOperations 该字段用来存储下载的操作)
    在上面queryCache的操作回调之后根据查找的情况调用[[self.imageDownloader downloadImageWithURL......]

  • 调用 addProgressCallback 该方法下的Block是创建 SDWebImageDownloaderOperation 下载队列用的

  • SDWebImageDownloaderOperation *operation = self.URLOperations[url]; 根据URL取,没有的话调用上面的Block创建下载队列返回

  • 返回 SDWebImageDownloadToken 对象 里面有url(用来key查询) 还有 downloadOperationCancelToken 存储回调Block(complete和Progress)

  • 创建的时候 NSOperationQueue 里面添加创建的任务,然后就会调用Start(需要重写) 进行下载,代理回调,接收数据

  • NSURLSession didReceiveData 返回image

  • 返回到SDWebImageManager的Block 二级缓存 内存和磁盘缓存起来 (这里的缓存是默认7天,应用退到后台会进行缓存清理)

  1. callCompletionBlockForOperation 调用最终的Block回调到用户UI控件进行赋值

伏笔:每次调用外层API的时候都会调用cancel的方法,原理博客上面有介绍了,这里说一下具体是怎么实现的。

首先:UI层面的API下面会调用 sd_internalSetImageWithURL 核心方法进行下载
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
这里会把返回的 SDWebImageCombinedOperation 和UI控件进行Category挂载

其次:SDWebImageMangae 调用loadImageWithURL 初始化 SDWebImageCombinedOperation
该对象的的CacheOperation是 SDImageCache 调用直接返回NSOperation赋值 (取消缓存操作)
代码底部还对loadOperation添加了一个Block operation.cancelBlock = ^{取消网络下载的操作};

最后:sd_cancelImageLoadOperationWithKey 调用取消
@interface SDWebImageCombinedOperation : NSObject 已经实现cancel代理
最终调用 SDWebImageCombinedOperation 里面的cache字段取消缓存操作,调用CancelBlock取消网络下载

几个核心逻辑没变,只是实现方式改变了,之前看过一遍,现在看一遍也很快,熟悉的朋友可以自己在看一遍

更新:SDWebImageDecoder是用来图片的解压缩(原理以及为什么)

SD内部已经帮我们把请求回来的数据或者缓存到本地的图片资源都进行了异步解压缩,因此不需要我们来做,简单了解下

图片压缩流程

假设我们使用 +imageWithContentsOfFile: 方法从磁盘中加载一张图片,这个时候的图片并没有解压缩;
然后将生成的 UIImage 赋值给 UIImageView ;
接着一个隐式的 CATransaction 捕获到了 UIImageView 图层树的变化;
在主线程的下一个 run loop 到来时,Core Animation 提交了这个隐式的 transaction ,这个过程可能会对图片进行 copy 操作,而受图片是否字节对齐等因素的影响,这个 copy 操作可能会涉及以下部分或全部步骤:
分配内存缓冲区用于管理文件 IO 和解压缩操作;
将文件数据从磁盘读到内存中;
将压缩的图片数据解码成未压缩的位图形式,这是一个非常耗时的 CPU 操作;
最后 Core Animation 使用未压缩的位图数据渲染 UIImageView 的图层。
在上面的步骤中,我们提到了图片的解压缩是一个非常耗时的 CPU 操作,并且它默认是在主线程中执行的。那么当需要加载的图片比较多时,就会对我们应用的响应性造成严重的影响,尤其是在快速滑动的列表上,这个问题会表现得更加突出。

点击打开链接摘自大神的博客,需要详细的可以点进去看看

个人理解:

1.首先PNG和JPEG都是图片的压缩格式,PNG是无损压缩,支持alpha,JPEG有损,可选1-100压缩比例

2.例如你有一张PNG的图片 20B,那么你对应的图片二进制数据也是20B的,解压缩后的图片就可能是几百几千B了

3.具体计算公式就是像素宽像素高每个像素对应的字节

4.那么当你进行图片渲染的时候,必须得到解压缩后的原始像素数据,才能进行图形渲染,这就是解压缩的原因

SD在SDWebImageDecoder这个文件中进行了强制解压缩,我们赋值给imageView的时候已经是解压缩的文件了,因此不会卡主主线程,不然默认是在主线程进行解压缩,图片一多,卡爆了

你可能感兴趣的:(2019-01-09SDW0)