首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SDWebImage源码阅读&原理解析

汇总记录:

本文基于SDWebImage 4.2.3版本进行分析和整理。

整体目录结构:

----处理不同平台(iOS、TV、OS、Watch)宏,以及根据文件名@2x、@3x进行图片处理和缩放

----添加cancel的delegate

+----

--------主要处理缓存逻辑,重点集中在:NSCache(Memory)、Disk读写、清理Old File

--------配置缓存参数:是否压缩、iCloud、InMemory、ReadingOption、时间和CacheSize

+----

--------主要提供下载的Operation操作

--------提供下载管理入口

+----

--------提供外层管理cache和download入口

--------预处理获取Image,主要应用预加载的地方

+----

--------提供类型判断和ImageIO类型转换

--------Data转UIImage(GIF)扩展

--------提供BitMap或者未知类型的Data转UIImage扩展

--------Data转WebP扩展

--------解压操作

--------提供顶层关于取消和下载记录的扩展

+----

--------整体Coders的入口,提供是否可Coder和Coder转发

--------主要说明Coder Delegate 需要实现的接口

--------PNG/JPEG的Encode和解压操作

--------GIF的Coder操作

--------WebP的Coder操作

--------辅助类,主要在GIF等动态图使用

--------辅助类,包括方向、Gif图合成等

整体组件结构

整体框架结构比较清晰,因为Decoder部分相对比较独立,业务逻辑处理主要在Cache、Downloader层级以及以上。

下文会以Cache、Downloader、Manager、Wrap的顺序进行分解,最后讨论Decoder部分。

1、缓存部分解析

缓存部分逻辑主要是在,包括如下几个方面:

新增

删除

查询

缓存管理(过期)

SDWebImage的缓存中,主要走了一套NSCache管理内存和根据传入的Key转换MD5作为文件名存储。以及创建了一个IO操作的Queue进行管理IO操作。

这里重点注意,任何耗时:包括IO读写、转码等操作,都不应该放到主线程里面使用。

缓存部分其他地方都比较简单易懂,直接看源码即可。

重点说下如下两个值得学习的地方:

1、通过NSOperation管理queue任务

查询缓存的时候,这里采用了NSOperation进行是否取消的操作,因为当下载/缓存内容过多时,毕定存在先后处理顺序的问题,这时候可能由于用户操作等需要取消当前缓存处理,那么NSOperation这里起的唯一作用就是提供取消操作。可以参考具体的Manager里面缓存调起逻辑。

2、申请系统后台时间处理任务

这里有个疑问点要注意,为啥会存在前后两部分都去释放Task任务。

iOS的后台任务有个背景,不管任何时候,都需要手动去调用endBackgroundTask结束后台任务,其实开启一个后台job的时候,因为时长有限,所以会存在两种结局:

在允许的时间内执行完成

规定时间内未执行完成

如上两种情况,在结束后都必须手动调用endBackgroundTask:;

2、下载器(Downloader)

下载部分,主要是提供了一个Operation和一个Manager,其中里面提供了常用的Operation操作,也支持自定义的下载逻辑(实现即可)。

2.1 SDWebImageDownloaderOperation 逻辑

该文件里面重点是Delegate:的设计和一种实现方式(PS:优秀的开源库基本都会设计一套接口,再做一套基础的实现)。

主要是提供内置的下载实现,重点是使用NSURLSessionTask进行下载,逻辑不复杂,详细的参考源码。里面重点有如下部分需要关注:

1、是共用的并发队列,而且不同的Op都是共用的同一个Queue,这里为啥要做成并发的呢?主要是优化多个线程callbacks的时间。

然后再配合操作来进行操作。

2、在URLSession的Delegate实现中,存在如下函数实现:

该部分重点是实现Https证书信任请求的,关于在iOS上的信任使用,可以搜索学习iOS上的Https。

2.2 SDWebImageDownloader说明

主要是基于进行任务的添加和管理。使用进行任务执行操作。

设置了同一时间最多可执行task为6.

提供设置Http头信息入口

允许使用自定义的Operation进行操作,如果没有指定,那么就用默认的

详细的逻辑参考代码即可,比较简单

3、针对通用组件封装(Wrap)

该部分的代码主要是在文件夹下面,除了以外,其他的涉及UIImage、UIButton等都是下载完成后赋值给到Image的区别,下载过程处理都是在中实现。

这里主要说下UIView+WebCache中的细节,其他的阅读源码即可,里面主要的逻辑函数为:

详细的步骤逻辑如下:

4、Decoder模块

Decoder模块部分的源码重点是在目录和两个地方,其中提供NSData、UIImage等的直接调用extend。核心实现还是基于Decoder。

相关模块的详细说明可以参考目录说明部分。

这里主要说下几个部分,主要包括个人觉得可能产生障碍的点,便于理解:

为啥要压缩和Decompressed?

和中的逻辑

大图片缩放逻辑辅助说明

4.1 为啥要压缩和Decompressed

我们都知道,在iOS中,我加载PNG和JPEG,直接调用就好,而且本来从网络上下载的图片也都是PNG或者JPEG的,又没用Zip等去进行压缩,为啥还有这么一个Decoder模块呢。

其实这里重点就是针对性能做优化,我们平时直接加载图片的时候,因为图片都很小,所以基本不会消耗时间,但是我们从url中拉取的图片,一般都是运营配置,基本都不小。

如果加载过本地未处理的PNG(文件比较大)的兄弟应该有过这种感觉,跑完加载的时候,刷出界面开始会白那么一下,图片才出来。那就是因为图片太大了。

那么针对PNG和JPEG,SDWebImage的Decompressed又是做什么操作呢,我们知道图片显示到设备上,是按照RGBA等显示,但是PNG和JPEG自身的格式并非RGBA的。这里的解压其实就是创建一个BitmapImage,先在非UI线程渲染图片,然后拿到UIImage去显示。

代码参考如下:

4.2和中的逻辑

这两个类里面,有部分函数主要是提供GIF图片的辅助,当我们从NSData拿到图片数据的时候,其实是拿到了多张图片的Data,当我们分成多张图(参考SDWebImageGIFCoder)后,我们要合成到UIImage的images中。

每个就代表了一张图片,每个图片有个播放时长,但是总的一个animationImage并未对每个Image进行时长设置。他的逻辑是怎样的呢?

假如我们有两张图AB,动画要显示A,显示B,那么我们可以指定显示四张图片:AAAB,总时长是。

所以当拿到GIF对应的UIImage和显示时长后,怎么去合成AAAB 和 4s 的时长呢,流程如下: -获取每个图片总时长,totalTimes -计算没个图片时长的最大公约数,再用每张图片的时长除以最大公约数,就是每张图片要显示的次数 -根据显示次数构建UIImage的Array,根据UIImage的Array和总时长,就能通过GIF转成UIImage动画了

4.3 大图片缩放逻辑辅助说明

图片缩放逻辑主要函数:

这里光看代码,肯定会一头雾水,其实逻辑很简单,避免要缩放的图片太大,采用的方式是将图片分割成一系列大小的小方块,然后每个方块去获取Image并draw到目标BitmapContext上。重点还是在于内存优化方面。

可以关注个人公众号联系我,欢迎大家一起沟通交流。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180120G0D9KR00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券