AFImageDownloader
The AFImageDownloader class is responsible for downloading images in parallel on a prioritized queue. Incoming downloads are added to the front or back of the queue depending on the download prioritization. Each downloaded image is cached in the underlying NSURLCache as well as the in-memory image cache. By default, any download request with a cached image equivalent in the image cache will automatically be served the cached image representation.
AFImageDownloader类是负责下载图片的,并且根据下载优先级,把新传入的下载添加在队列的前面或后面。每个下载好的图片不仅被缓存在底层的NSURLCache中(NSURLCache只是被用来自动缓存网络请求,并没有进行图片缓存),也缓存在内存中的图片缓存中(上篇写的AFAutoPurgingImageCache类)。默认情况下,如果请求的图片有缓存的话,会直接返回缓存图片。
1、简单了解下AFImageDownloader
的主要属性
|
|
2、AFImageDownloader
有两个属性queuedMergedTasks
,mergedTasks
用来存储另一个对象AFImageDownloaderMergedTask
(用来操作下载任务合并的对象)
|
|
3、AFImageDownloaderMergedTask
有一个属性responseHandlers
来存储返回结果操作的对象AFImageDownloaderResponseHandler
|
|
4、返回到昨天那个处理图片下载的核心方法
|
|
返回值是AFImageDownloadReceipt
,而它的声明方法只有一个,因此需要一个NSURLSessionDataTask对象(iOS 7.0 以后,代替NSURLConnection
用来处理数据请求的类)
5、声明一个NSURLSessionDataTask对象,用来创建AFImageDownloadReceipt
。__block
修饰,用来在block中更改task值,
|
|
6、在一个串行队列里中同步执行,直至结束,如果task存在,创建AFImageDownloadReceipt
并返回,否则返回nil
|
|
7、再次对URLRequest进行判断
|
|
8、如果请求已经存在,并且根据url地址能够找到AFImageDownloaderMergedTask,直接返回对应的task,然后外层赋值。
这里可以看出来
AFImageDownloaderMergedTask
类的作用:- 当请求地址是同一个的时候,并且第一个请求正在进行中,后续就不再向服务器发送请求。这也是AFNetwork比较优化的一点,主要用来多张不同的imageView同时请求一个URL地址的情况。跟上篇那个同一张图片多次请求一个URL地址的情况比较一下(第6点)。
- 不同请求对应的成功失败块也没有统一处理,根据下载任务对应的唯一标识
receiptID
和成功失败块,生成AFImageDownloaderResponseHandler
,来进行分别处理。 - 而合并任务的task就是外层需要的task,即创建
AFImageDownloadReceipt
的task
如果是首次请求,后面肯定会有对应的赋值操作,往下看
|
|
9、 根据缓存策略在缓存中是否进行第二次的查找
|
|
10、创建网络下载任务,进行图片下载,并处理返回结果
11、对应第8点中的取值操作,这里进行赋值操作。注意一个关键字mergedTaskIdentifier
,是合并任务的唯一标识
|
|
12、当前任务创建已经完成,根据线程中正在进行的请求数量来决定,是进行下一个任务,还是等待。
|
|
13、下面线深入12中的方法,最后再啃硬骨头10中的方法
14、最后来处理当图片下载任务(即网络请求任务)已经完成,之后的操作
首先请求结果的处理都是在异步线程中执行的,避免线程阻塞,一直在等待网络请求完成
1dispatch_async(self.responseQueue, ^{ });针对第8点,第11点,所有针对返回结果的操作都是跟
AFImageDownloaderMergedTask
绑定的,所以找到对应于url地址的合并任务,并且根据合并任务的唯一标识判断是否同一个,12345AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) {}跟之前从字典获取的其实是同一个合并任务,这句话主要用来任务完成了,在字典中移除键值对
1mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier];遍历同一个url对应的所有的失败块,都失败了,回调失败信息
1234567891011// 失败处理if (error) {for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {if (handler.failureBlock) {dispatch_async(dispatch_get_main_queue(), ^{handler.failureBlock(request, (NSHTTPURLResponse*)response, error);});}}}成功情况下,先进行图片缓存,再对所有的成功块,进行成功信息回调
12345678910[strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {// 成功回调处理if (handler.successBlock) {dispatch_async(dispatch_get_main_queue(), ^{handler.successBlock(request, (NSHTTPURLResponse*)response, responseObject);});}}最后,请求结束了,当前执行的请求数量-1,
1234567- (void)safelyDecrementActiveTaskCount {dispatch_sync(self.synchronizationQueue, ^{if (self.activeRequestCount > 0) {self.activeRequestCount -= 1;}});}如果还有需要执行的线程,就启动下一个线程
12345678910111213- (void)safelyStartNextTaskIfNecessary {dispatch_sync(self.synchronizationQueue, ^{if ([self isActiveRequestCountBelowMaximumLimit]) {while (self.queuedMergedTasks.count > 0) {AFImageDownloaderMergedTask *mergedTask = [self dequeueMergedTask];if (mergedTask.task.state == NSURLSessionTaskStateSuspended) {[self startMergedTask:mergedTask];break;}}}});}
目前这就是AFNetwork中加载图片的所有流程,当然数据请求还没有涉及,想研究这个入口的时候再进行深入
总结:
1. AFNetwork把加载图片的任务都放入一个字典中,然后把任务对应的网络请求放入数组中,然后按顺序执行
2. 在图片加载过程中,除了在针对请求结果处理的时候是异步进行的,其他全是同步进行的
3. 一家之言,请多指教