SDWebImage是我们非常常用的一个关于图片下载缓存的框架。下面的源码分析是基于版本3.8。下面是gitHub上的介绍:
主要作用:
1、为UIiamgeView,UIbutton 等控件加载网络图片,并且进行缓存管理
2、一个异步图片下载工具
3、一个异步的内存和硬盘的图片缓存,提供自动的缓存处理
4、异步的图片解码
5、保证相同的URL不会多次下载
6、保证不合法的URL不会被多次下载
7、保证主线程不会被阻塞
8、自定义
9、使用GCD 和 ARC
为什么使用SDWebImage而不是NSURLCache或是AFN?
1、在IOS 5之后可以使用NSURLCache 进行http缓存,但是每次缓存的是原始数据,每一次使用的时候,需要将原始数据解析成UIImage,导致额外的数据解析和内存占用,AFN就是使用NSURLCache进行缓存的。
2、UIImageView中使用image对象的时候,图片的解码是在主线程中运行的!而SDWebImage会强制将解码操作放到子线程中。(PNG,jpeg图片对象,转换为位图对象)
3、使用NSCache作为内存缓存,避免了对象的重复copy,并且保存的是位图对象,避免了重复的解码。
4、SDWebImage 完全绕过了Http请求关于缓存的控制,大大加快了缓存速度。
根据图片的url缓存,所以一旦改变图片,必须改变地址?(不会去判断服务器关于缓存处理的response header )对于类似facebook 头像这样的例子,可以使用下面的方式,这种方式,会参考请求头。
5、提供了大量的关于图片的扩展选择。
当我们调用这个sd_setImageWithURL,这个方法的时候发生了什么?
1、停止所有和这个View相关的Operation。
这里还有一个operation 字典:UIView+WebCacheOperation 有一个关联对象,用来保存这个View相关的Operation
operation字典 UIView+WebCacheOperation的cancle 当前所有相关的Operation(相关类的介绍:
UIImageView (WebCache):
1、提供相关的下载方法
UIView (WebCacheOperation)
1、提供与view相关的loadOperation(字典),可以通过这个字典取消该View相关的Operation)
2、SDWebImageManager的downloadImageWithURL的方法
(1)、非法Url判断
(2)、定义一个SDWebImageCombinedOperation,用这个Operation管理下载和缓存的Operation,并把它加到runningOperations中
(3)、产生缓存的key,这里的缓存的key,可以进行自定义
自定义缓存key(相关类介绍:
SDWebImageOperation
1、定义的一个基础协议,带有cancle方法
SDWebImageCombinedOperation
1、混合Operation,包含缓存Operation还有管理下载Operation
SDWebImageManager
SDWebImageManager(单例)
1、中间层,调用缓存,和下载(管理所有的Operation)
2、提供SDWebImageManagerDelegate(作为扩展),还有三种block
)
3、SDImageCache的queryDiskCacheForKey方法,开始寻找磁盘缓存和内存缓存
(1)、内存缓存,使用的NSCache(避免重复拷贝)
(2)、一个IOQueue,进行磁盘缓存的查询,进行异步查询
在io队列里面异步查询(3)、如果磁盘中存在这张图片,那么进行判断对应的图片格式(包括动态图)
设置图片的方向(Orientation),scale,并且进行解码工作。这里强制进行异步解码,将编码之后的图片格式(png,jpeg)转换成位图对象。
进行缓存查找操作相关的类:
SDImageCache(单例)
1、缓存管理,缓存配置,缓存清理,缓存查找(异步执行)
2、内存缓存,使用的是位图,磁盘缓存使用的是编码之后的图片
UIImage (ForceDecode)
1、图片解码,相关格式图片图像,转换为位图对象
强制解码:将编码之后的image对象转换为位图(点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的)
一般下载或者从磁盘获取的图片是PNG或者JPG,这是经过编码压缩后的图片数据,不是位图,要把它们渲染到屏幕前就需要进行解码转成位图数据,而这个解码操作比较耗时,iOS默认是在主线程解码,所以SDWebImage将这个过程放到子线程了。
同时因为位图体积很大,所以磁盘缓存不会直接缓存位图数据,而是编码压缩后的PNG或JPG数据。
4、当没有缓存时候,使用SDWebImageDownloader进行下载,
(1)、将所有的callback放在一个字典数组中管理。(用url作为key)。
(2)、封装request对象,加入用户自带的一些配置
注:为了避免重复下载,默认,不进行NSUrlCache缓存,不使用系统的缓存
避免重复下载(3)产生SDWebImageDownloaderOperation,下载操作
(4)设置这个operation 的相关属性,比如优先级,还有executionOrder,执行顺序(先进后出或是先进先出),(实现的方式,是通过Operation的相互依赖)
关于执行顺序的枚举值 执行顺序设定的实现相关的类:
SDWebImageDownloader
1、图片下载类,图片的下载管理
2、提供大量扩展(下载设置)
SDWebImageDownloaderOptions
SDWebImageDownloaderExecutionOrder,下载的顺序
SDWebImageDownloaderProgressBlock
SDWebImageDownloaderCompletedBlock
SDWebImageDownloaderHeadersFilterBlock
maxConcurrentDownloads(最大并发数)
3、操作callBack使用的的调度方式, dispatch_barrier_sync,dispatch_barrier_async管理barrierQueue(类似于锁?),之后添加的Operation,会等这个任务执行之后才会继续执行
5、使用SDWebImageDownloaderOperation,进行下载,在下载过程中,调用progressBlock,下载结束,调用completeBlock。拿到网络数据,转成图片格式,设置方向,scale,进行图片解码,返回的图片是位图对象
管理下载操作,3版本使用的是NSURLConnection,之后使用的是NSURLSession(异步下载)
(1)、提供后台下载,开启运行循环(不然代理不能正常调用)
(2)在NSURLConnection的代理中,处理下载功能
(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 拿到服务器响应,判断是否正确下载
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data下载过程管理(调用progressBlock),这里提供边下载,边显示的功能
下载图片,进行异步的强制解码6、回到SDWebImageManager,
(1)处理Image对象,如果实现了相关的代理方法就调用代理方法,
(2)之后使用imageCache,保存图片信息。位图对象直接保存到内存缓存中,编码图片,保存到磁盘中。(这里是否能在之前就直接保存到磁盘,节省一段图片编码的过程)。内存中保存位图,是为了避免重复解码。磁盘中保存编码之后的图片是为了节省空间。
(3)从全局的Operation字典,移除相关的Operation
将下载后的图片进行缓存7、回到UIImageView (WebCache),回到主线程,设置图片,调用结束
更新UI,回到主线程其他注意的点:
1、缓存清理,当收到这三个通知的时候进行缓存的清理
缓存清理的策略,这里的IO操作都是异步处理的。
(1)删除过期缓存(苹果官方规定最长的缓存周期是1周)
(2)计算当前缓存文件的总大小,比较设置的最大缓存,如果超出的话,那么就继续删除(按照缓存文件创建的顺序),直到小于最大缓存为止
缓存策略2、SDWebImagePrefetcher,这个类,提供提前缓存图片的方法(可以用来作用于banner等),提供批量的下载。
3、对于UIView (WebCacheOperation),当我们移除Operation的时候,发生了什么?其实取消的是SDWebImageCombinedOperation
(1)、取消cacheOperation
(2)、执行cancelBlock,这里的cancleBlock,关闭的就是下载的Operation
(3)、将这个Operation,移除整个Operation字典
网友评论