一行行看SDWebImage源码(二)

276769-f7b02c377c44f9ea

地表最强

最近真的真的太太太忙了,都是抽空写的,各种事情,html,iOS客户端升级,炸了


上一篇我们基本上看完了SDWebImage整个工作流程,下面我们具体看一下缓存下载图片中涉及到的相关的类

SDWebImageDownloader

SDWebImageManager实现下载依赖于下载器:SDWebImageDownloader,下载器负责管理下载任务,而执行下载任务是由SDWebImageDownloaderOperation操作完成

SDWebImageManager实现下载 就是调用下面这个方法:

我们还是先来看看SDWebImageDownloader里面都写了些什么
SDWebImageDownloader.h

这些选项主要涉及到下载的优先级,缓存,后台任务执行,cookie处理以及证书认证几个方面,在创建下载操作的时候可以使用组合的选项来完成一些特殊的需求

定义里两个常量,后面通知的时候用的,这里的常量是全局常量

全局常量:不管你定义在任何文件夹,外部都能访问

局部常量:用static修饰后,不能提供外界访问(只能在赋值的.m文件使用,外界不可访问)

定义了三个block

  • 第一个返回已经接收的图片数据的大小,未接收的图片数据的大小,- (void)sd_setImageWithPreviousCachedImageWithURL: placeholderImage: options: progress:completed:
    这个方法里面就有用到,因为图片的下载是需要时间的,所以这个block回调不止回调一次,会一直持续到图片完全下载或者下载失败才会停止回调
  • 第二个block回调 下载完成的图片 , 图片的数据 , 如果有error返回error ,以及下载是否完成的BOOl值
  • 第三个是header过滤:设置一个过滤器,为下载图片的HTTP request选取header.最终使用的headers是经过这个block过滤时候的返回值

定义的属性

看完这些属性后我们在来看SDWebImageDownloader里面的两个核心方法,其他的方法会捎带说一下
第一个就是一开始我们说的,SDWebImageManager会调用的方法

先来看看-addProgressCallback:completedBlock:forURL:createCallback:里面都做了些什么

下面重点也是不太好理解的东西,我也是又系统地复习了一下GCD,琢磨了有段时间才继续写的

如果你GCD非常熟悉就跳过吧,不熟悉就先来看看我总结的GCD吧,写的比较好理解,先来看看 几个概念

Serial 串行 Concurrent并发
任务串行执行每次只有一个任务执行
任务并发执行就是同一时间可以有多个任务被执行

Synchronous 同步
一个同步函数只有在它完成预定的任务才返回(返回的意思是:返回当前线程,线程继续向下执行任务,你可以自己做个测试用一个同步函数,任务里面sleep(3);测试一下就明白了)

Asynchronous 异步
一个异步函数,会立即返回,预定任务会完成,但是不会等到这个任务完成才返回

Queues 队列
GCD提供 dispatch queues来处理代码,这些队列管理你提供给GCD的任务并用FIFO顺序执行,这保证了第一个被添加到队列里的任务会是队列中第一个执行的,第二个被添加的任务第二个开始执行,如此直到队列的终点
只能保证任务开始的顺序不能保证任务结束的顺序

Serial Queues 串行队列
串行队列的任务一次执行一个,每一个任务只有在前一个任务完成的时候才开始,但是你不知道一个任务(block)和下一个开始之间的时间长度

Concurrent Queues 并发队列
在并发队列中的任务能得到的保证是它们会被按照被添加的顺序开始执行,任务能以任意顺序完成,但是你不知道什么时候才开始运行下一个任务,或者任意时刻有多少block在运行,这完全取决于GCD

Queue Type 队列类型
主队列(main queue),和其它串行队列一样,这个队列中的任务一次只能执行一个,然后它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新UI的线程,这个队列就是用于发消息给UIView或发送通知的

全局调度队列(Global Dispatch Queues),它分了四种优先级(任务执行的优先级):background , low , default , high
Apple的API也会使用这些队列,所以你添加的任何任务都不会是这些队列唯一的任务

自己创建的串行队列 或者并发队列

GCD提供的函数
dispatch_async 异步 , 与其他线程无关
dispatch_sync 同步,阻塞其他线程
dispatch_apply 重复执行
dispatch_after 延迟执行
dispatch_barrier_async dispatch_barrier_sync(下面细讲)

只列举了一些常用的GCD函数,并不完全

GCD的使用呢,总结起来就是先选用一个GCD提供的函数,传入一个你要调用的队列(三种队列类型的一种)和一个block(任务),
队列会在轮到这个block执行的时候执行这个block

注意:队列是用来存放任务的,队列并不等于线程,队列中存放的任务最后都要由线程来执行

再回到刚才要看的部分,dispatch_barrier_sync是我们选用的GCD提供的函数,self.barrierQueue是存放任务的队列,block里面是要执行的任务

先来看看dispatch_barrier_sync
Dispatch Barrier解决多线程并发读写一个资源发生死锁
sync说明了这是个同步函数,任务不会立即返回,会等到任务执行结束才返回
使用dispatch_barrier_sync此函数创建的任务会首先去查看队列中有没有别的任务要执行,如果有则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等到此方法中任务执行后才能执行,利用这个方法可以控制执行顺序
Dispatch Barrier确保提交的block是指定队列中特定时段唯一在执行的一个.在所有先于Dispatch Barrier的任务都完成的情况下这个block才开始执行.轮到这个block时barrier会执行这个block并且确保队列在此过程 不会执行其他任务.block完成后才恢复队列

这是用户自己创建的队列,DISPATCH_QUEUE_CONCURRENT代表的是它是一个并行队列,为什么选择并发队列而不是串行队列我们来想一下:
串行队列可以保证任务按照添加的顺序一个个开始执行,并且上一个任务结束才开始下一个任务,这已经可以保证任务的执行顺序(或者说是任务结束的顺利)了,但是并行队列不一样,并发队列只能保证任务的开始,至于任务以什么样的顺序结束并不能保证但是并发队列使用Barrier却是可以保证的

这部分就先到这里继续向下看:

URLCallbacks是一个可变字典,key是NSURL类型,value为NSMutableArray类型,value(数组里面)只包含一个元素,这个元素的类型是NSMutableDictionary类型,这个字典的key为NSString类型代表着回调类型,value为block,是对应的回调
这些代码的目的都是为了给url绑定回调

继续向下看:

如果url第一次绑定它的回调,也就是第一次使用这个url创建下载任务则执行一次创建回调
在创建回调中 创建下载操作(下载操作并不是在这里创建的),dispatch_barrier_sync执行确保同一时间只有一个线程操作URLCallbacks属性,也就是确保了下面创建过程中在给operation传递回调的时候能取到正确的self.URLCallbacks[url]值,同事确保后面有相同的url再次创建的时候if (!self.URLCallbacks[url])分支不再进入,first==NO,也就不再继续调用创建回调,这样就确保了同一个url对应的图片不会重复下载

以上这部分代码总结起来只做了一件事情:在barrierQueue队列中创建下载任务
至此下载的任务都创建好了,下面该轮到下载的操作了:

NSURLCredential 身份认证

认证过程
1.web服务器接收到来自客户端的请求
2.web服务并不直接返回数据,而是要求客户端提供认证信息,也就是说挑战是服务端向客户端发起的
2.1要求客户端提供用户名与密码挑战 NSInternetPassword
2.2 要求客户端提供客户端证书 NSClientCertificate
2.3要求客户端信任该服务器
3.客户端回调执行,接收到需要提供认证信息,然后提供认证信息,并再次发送给web服务
4.web服务验证认证信息
4.1认证成功,将最终的数据结果发送给客户端
4.2认证失败,错误此次请求,返回错误码401


Web服务需要验证客户端网络请求
NSURLConnectionDelegate 提供的接收挑战,SDWeImage使用的就是这个方案

至此下载管理 SDWebImageDownloader到这里就算结束了,它的主要作用就是创建下载任务,管理下载任务(取消,下载等状态改变)这里的重点就是对self.barrierQueue的理解,最后我们来看看SDWebImageDownloaderOptions下载操作和下载过程的实现


SDWebImageDownloaderOptions

它的作用就是网络请求的配置,进行网络请求以及数据处理
依旧先来看看它公开声明的属性和方法

然后继续看SDWebImageDownloaderOperation.h

初始化方法,这个就是初始化一个SDWebImageDownloaderOperation实例,没什么看点

但是下面这个方法- (void)start就是关键了,它是对NSOperation- (void)start的重写,这个方法是执行下载任务的核心代码

最后,我们来看NSURLConnection (delegate)
1.connection: didReceiveResponse:

2.connection: didReceiveData拼接数据的协议

3.connectionDidFinishLoading:这个方法完成以后,代理不再会接收人和connection发送的消息,标志着图片下载完成,一般下载任务正常结束之后就会执行一次这个方法

到这里,看的也差不多了,认真看完感觉这个作者太厉害了,也真的学习到了很多,欢迎交流,也希望大家自己有空了也看一下,这次真的是拖了一个月因为有的东西我没明白就看了好多天也查了 各种资料,这次也算是尽力写好了吧,惭愧

包厢里的狂欢,曲终人散
have Fine
以上

1 6 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部