AFNetworking源码学习

早在一年前,自己就研究过AFN的源码,但是,好多地方还没有完全理解。虽然最近一直在用Swift开发,但是这两天看到了人们争论关于AFN常驻线程的问题,所以又简单的过了一遍。在此,先向大家推荐一个关于AFN的博客,博主写了一系列关于AFN的源码解析和实现原理,因为AFN3.x和AFN2.x相比有较大的更新,文中也有相关的介绍。另外,我单独从中摘出了AFN中关于常驻线程这块的解释。

大神博客地址:https://www.jianshu.com/p/856f0e26279d  (注:里边有好几篇文章)


一、关于AFN2.x中常驻线程的解释:

首先如果我们用NSURLConnection,我们为了获取请求结果有以下三种选择:

  1. 在主线程调异步接口
  2. 每一个请求用一个线程,对应一个runloop,然后等待结果回调。
  3. 只用一条线程,一个runloop,所有结果回调在这个线程上。

很显然AF选择的是第3种方式,创建了一条常驻线程专门处理所有请求的回调事件,这个模型跟nodejs有点类似,我们来讨论讨论不选择另外两种方式的原因:

  1. 试想如果我们所有的请求都在主线程中异步调用,好像没什么不可以?那为什么AF不这么做呢...在这里有两点原因(楼主个人总结的,有不同意见,欢迎讨论):
  • 第一是,如果我们放到主线程去做,势必要这么写:
 [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES] 

这样NSURLConnection的回调会被放在主线程中NSDefaultRunLoopMode中,这样我们在其它类似UITrackingRunLoopMode模式下,我们是得不到网络请求的结果的,这显然不是我们想要的,那么我们势必需要调用:

[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 

把它加入````NSRunLoopCommonModes```中,试想如果有大量的网络请求,同时回调回来,就会影响我们的UI体验了。

  • 另外一点原因是,如果我们请求数据返回,势必要进行数据解析,解析成我们需要的格式,那么这些解析都在主线程中做,给主线程增加额外的负担。
    又或者我们回调回来开辟一个新的线程去做数据解析,那么我们有n个请求回来开辟n条线程带来的性能损耗,以及线程间切换带来的损耗,是不是一笔更大的开销。

所以综述两点原因,我们并不适合在主线程中回调。

  1. 我们一开始就开辟n条线程去做请求,然后设置runloop保活住线程,等待结果回调。
  • 其实看到这,大家想想都觉得这个方法很傻,为了等待不确定的请求结果,阻塞住线程,白白浪费n条线程的开销。

综上所述,这就是AF2.x需要一条常驻线程的原因了



二、关于AFN3.x中 self.operationQueue.maxConcurrentOperationCount = 1 的设置

这个operationQueue就是我们代理回调的queue。这里把代理回调的线程并发数设置为1了。

1、首先我们要明确一个概念,这里的并发数仅仅是回调代理的线程并发数。而不是请求网络的线程并发数。请求网络是由NSUrlSession来做的,它内部维护了一个线程池,用来做网络请求。它调度线程,基于底层的CFSocket去发送请求和接收数据。这些线程是并发的

2、明确了这个概念之后,我们来梳理一下AF3.x的整个流程和线程的关系:

  • 我们一开始初始化sessionManager的时候,一般都是在主线程,(当然不排除有些人喜欢在分线程初始化...)
  • 然后我们调用get或者post等去请求数据,接着会进行request拼接,AF代理的字典映射,progressKVO添加等等,到NSUrlSessionresume之前这些准备工作,仍旧是在主线程中的。
  • 然后我们调用NSUrlSessionresume,接着就跑到NSUrlSession内部去对网络进行数据请求了,在它内部是多线程并发的去请求数据的。
  • 紧接着数据请求完成后,回调回来在我们一开始生成的并发数为1的NSOperationQueue中,这个时候会是多线程串行的回调回来的。(注:不明白的朋友可以看看雷纯峰大神这篇iOS 并发编程之 Operation Queues
  • 然后我们到返回数据解析那一块,我们自己又创建了并发的多线程,去对这些数据进行了各种类型的解析。
  • 最后我们如果有自定义的completionQueue,则在自定义的queue中回调回来,也就是分线程回调回来,否则就是主队列,主线程中回调结束。

3)最后我们来解释解释为什么回调Queue要设置并发数为1:

  • 我认为AF这么做有以下两点原因:
    1)众所周知,AF2.x所有的回调是在一条线程,这条线程是AF的常驻线程,而这一条线程正是AF调度request的思想精髓所在,所以第一个目的就是为了和之前版本保持一致。
    2)因为跟代理相关的一些操作AF都使用了NSLock。所以就算Queue的并发数设置为n,因为多线程回调,锁的等待,导致所提升的程序速度也并不明显。反而多task回调导致的多线程并发,平白浪费了部分性能。
    而设置Queue的并发数为1,(注:这里虽然回调Queue的并发数为1,仍然会有不止一条线程,但是因为是串行回调,所以同一时间,只会有一条线程在操作AFUrlSessionManager的那些方法。)至少回调的事件,是不需要多线程并发的。回调没有了NSLock的等待时间,所以对时间并没有多大的影响。(注:但是还是会有多线程的操作的,因为设置刚开始调起请求的时候,是在主线程的,而回调则是串行分线程。)

当然这仅仅是我个人的看法,如果有不同意见的欢迎交流~


三、AFNetworking到底做了什么?

一. 首先我们需要明确一点的是:
相对于AFNetworking2.x,AFNetworking3.x确实没那么有用了。AFNetworking之前的核心作用就是为了帮我们去调度所有的请求。但是最核心地方却被苹果的NSURLSession给借鉴过去了,嗯...是借鉴。这些请求的调度,现在完全由NSURLSession给做了,AFNetworking3.x的作用被大大的削弱了。
二. 但是除此之外,其实它还是很有用的:

  1. 首先它帮我们做了各种请求方式request的拼接。想想如果我们用NSURLSession,我们去做请求,是不是还得自己去考虑各种请求方式下,拼接参数的问题。
  • 它还帮我们做了一些公用参数(session级别的),和一些私用参数(task级别的)的分离。它用Block的形式,支持我们自定义一些代理方法,如果没有实现的话,AF还帮我们做了一些默认的处理。而如果我们用NSURLSession的话,还得参照AF这么一套代理转发的架构模式去封装。

  • 它帮我们做了自定义的https认证处理。看过楼主之前那篇AFNetworking之于https认证的朋友就知道,如果我们自己用NSURLSession实现那几种自定义认证,需要多写多少代码...

  • 对于请求到的数据,AF帮我们做了各种格式的数据解析,并且支持我们设置自定义的code范围,自定义的数据方式。如果不在这些范围中,则直接调用失败block。如果用NSURLSession呢?这些都自己去写吧...(你要是做过各种除json外其他的数据解析,就会知道这里面坑有多少...)

  • 对于成功和失败的回调处理。AF帮我们在数据请求到,到回调给用户之间,做了各种错误的判断,保证了成功和失败的回调,界限清晰。在这过程中,AF帮我们做了太多的容错处理,而NSURLSession呢?只给了一个完成的回调,我们得多做多少判断,才能拿到一个确定能正常显示的数据?

  • ......

  • ...

光是这些网络请求的业务逻辑,AF帮我们做的就太多太多,当然还远不仅于此。它用凝聚着许多大牛的经验方式,帮我在有些处理中做了最优的选择,比如我们之前说到的,回调线程数设置为1的问题...帮我们绕开了很多的坑,比如系统内部并行创建task导致id不唯一等等...

三. 而如果我们需要一些UIKit的扩展,AF则提供了最稳定,而且最优化实现方式:

  • 就比如之前说到过得那个状态栏小菊花,如果是我们自己去做,得多写多少代码,而且实现的还没有AF那样质量高。
  • 又或者AFImageDownloader,它对于组图片之间的下载协调,以及缓存使用的之间线程调度。对于线程,锁,以及性能各方面权衡,找出最优化的处理方式,试问小伙伴们自己基于NSURLSession去写,能到做几分...

所以最后的结论是:AFNetworking虽然变弱了,但是它还是很有用的。用它真的不仅仅是习惯,而是因为它确实帮我们做了太多。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用AFNetworking库下载文件时,有几种常见的方式。第一种方式是使用AFHTTPRequestOperation进行文件下载,需要传入文件的下载地址URL、自定义的文件名fileName以及下载到的文件路径d_path。 另一种方式是使用AFHTTPSessionManager结合NSURLSessionDownloadTask进行文件下载。同样需要传入文件的下载地址URL和下载到的文件路径d_path。 此外,还可以使用AFNetworking库来实现文件的断点下载功能。通过对AFNetworking3.0版本的学习,你可以了解到如何使用AFNetworking库来实现文件断点下载,并且可以获取一些有价值的参考信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [AFNetworking从指定网址下载文件的两种方式总结](https://blog.csdn.net/u014063717/article/details/52232858)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [iOS利用AFNetworking3.0——实现文件断点下载](https://download.csdn.net/download/weixin_38607784/12786948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值