多阅读别人的源码是一种学习,尤其是牛掰人的源码,可惜自己是个渣渣进不了BAT这种大厂,所以只能靠阅读优秀的第三方框架来增长自己的知识面了,就算是这样也是才开始,不过亡羊补牢未为晚矣,啥时候醒悟都不晚,所以坚持坚持,
如题所示,首先看上的就是AFNetWorking的源码,重要性不多说了,我觉得iOS程序员百分百都用过了,没用过估计不是大牛,就是异类啦,封装的没的说,我这水平也难一下子窥其全貌,在上班时间偷偷的看了几天才总算了解各大概,写下了不求有多少人会看到,但求把自己的理解写下来避免忘记,水平再差也算一点心得嘛。
不多说先上图拉出来溜溜:
![](https://img.haomeiwen.com/i2368622/29940b19775be7b7.png)
先说个大概,然后每个类分别展开,最后在分析一下运行过程,我觉得能掌握到这步就差不多啦,剩下再多的,就看你的内功如何了。
AFHTTPSessionManager
为啥说AFN牛逼呢,就是因为他给用户提供的接口很简单,只要传入简单的参数就可以在block中拿到数据,非常方便,然后这种方便不代表实现起来方便(有点跑题)。AFHTTPSessionManager就是暴露给用户的最外层封装,给用户很简单的函数接口,来实现很cool的功能。
![](https://img.haomeiwen.com/i2368622/90fc6ef62bd1291c.png)
平时使用率95%的get 和 post 接口一目了然。前面几函数都是初始化函数,最后接种到此函数对,URLSession 进行简单的配置。
![](https://img.haomeiwen.com/i2368622/19ef7c08cf0228ae.png)
AFHTTPSessionManager类继承自AFURLSessionManager类,所以在此类可以看到很多super方法,这些都是配置URLSession的,这个下面在展开。
经过初始化后当用户想要调用网络请求时,只要一个函数即可
![](https://img.haomeiwen.com/i2368622/3405df8c815ed1d1.png)
其实所有的网络请求都是调用中间的一个函数,封装出来这么多函数就只能怪oc固有的坑了,
AFURLSessionManager
此类为AFN的核心类,封装了URLSession 历史不多说啦,如果有不明白的亲们可以Google 一下URLSession,苹果爸爸全面推荐,已经把老的废除了,同时还推荐一本入门好书,读了它腰不酸,腿不疼了,一口气撸一天也不需要营养快线了。
![](https://img.haomeiwen.com/i2368622/dd2e7a0c6c0060c6.png)
接着言归正传,正式初始化AFURLSessionManager的时候,干了几件事
![](https://img.haomeiwen.com/i2368622/3cb4b6038a8f1f7e.png)
最开始初始化了一个默认的配置[NSURLSessionConfiguration defaultSessionConfiguration] ,这货简单就是可以配置http请求的,这跟URLSession的设计有关,每个请求都可以独立配置。
然后创建了一个最大运行数为1的队列,说白了就是同步的啊,这样我觉得可以避免资源竞争,而且可以节省资源,(注:AFN2的时候此处是创建一条常驻线程,其实效果是一样的,如果每次请求的时候都开线程,请求后再关闭,这期间就会浪费好多资源啊,所以单开一个常驻线程,这样所有的请求来的时候都走这一个线程,省资源,这也算一个曝光率比较高的面试题,写到这想到了所以说一下)。
然后初始化了一个NSURLSession进行网络通信用。然后初始化一个解析返回报文体的实例,默认初始化的是json解析的(大部分网络都是这个套路)。
然后初始化一个AFSecurityPolicy类,这个类是负责https加密,以及协商秘钥xxx等操作的,后学再讲,因为这个类是单独的,不知道它并不影响其他的学习。
然后开始又初始化了网络监控AFNetworkReachabilityManager,这货也是可以单独使用的,功能说白了很简单,就是通过桥接bridge 来监控当前的网络状态:无网、未知网络、WiFi、手机网络等。
然后初始化一个字典,会把该session下的所有Task通过ID存到字典里,并且初始化一个NSLock,这把锁基本上就是锁住这个字典的,因为AFN整体上来说是异步的,避免数据混乱造成资源竞争。
一个session里面可能存在三种Task: 数据传输、下载、上传。便利session 把缓存的session 都存到字典里。并且为task设置delegate。
![](https://img.haomeiwen.com/i2368622/943b0afec4664522.png)
此函数先进行了初始化了代理AFURLSessionManagerTaskDelegate,主要的是初始化了一个NSProgress实例(我之前也没用过,是封装的管理进度的类,主要是用于管理下载,和上传进度的),
![](https://img.haomeiwen.com/i2368622/8f7760d0a645aa4c.png)
然后把Task的代理用字典保存起来,在此处加锁,为了防止资源混乱原因不说啦,然后设置通知,让外界可以观察到这一变化。
![](https://img.haomeiwen.com/i2368622/2252157f9a942d80.png)
三种代理设置代理的方式基本上相同,只不过在添加下载代理中添加了如果有下载的资源为其单独添加下载资源的回调。
![](https://img.haomeiwen.com/i2368622/bcdfcba5b653aea3.png)
再往后不得不说创建Task任务了
![](https://img.haomeiwen.com/i2368622/77fa528b0bd777fe.png)
再此处创建了一个全局的串行队列,保证发出请求不会错乱(本人所在公司是带蓝牙硬件的,前人遗留的‘财富’中根本没有这东西,导致经常会出现很诡异的数据问题,满满的都是坑啊),还有个人认为这种用static的这种方式不错,可以多用呢
![](https://img.haomeiwen.com/i2368622/dc1bed3491f51d61.png)
同样如之前的代码,创建Task也分三种,每种都有一点不一样
![](https://img.haomeiwen.com/i2368622/ae9cd465c3690fcd.png)
创建uploadTask中添加了对最大上传数的判断,AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask最大默认上传数为3 而且根据上传的是文件还是data还有不同的封装,
剩下封装了一堆NSURLSessionDataDelegate 和NSURLSessionDownloadDelegate 基本了,基本上都是通过回调的方式搞的,让用户能比较方便的使用AFN,这玩意可以参看这苹果官方api慢慢看,功能一目了然。
剩下还有AFURLSessionManagerTaskDelegate在前面也介绍了,他的初始化,简单的来说URLSession 就是通过NSURLSessionConfiguration实现对网络条件的配置,通过NSURLSession创建加载http请求的信息,通过Task来实现动作。这是我个人的理解不一定对哈,但是最少简单明了,感觉又说跑了哈。
这个类中最关键的就是接收到数据传输解析数据的方法啦
![](https://img.haomeiwen.com/i2368622/d285cabf0cfdbb88.png)
实现了**- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask )task didCompleteWithError:(NSError )error;代理,官方解释
告诉代理任务完成传输数据。
服务器错误不会通过错误参数报告。代表通过错误参数收到的唯一错误是客户端错误,例如无法解析主机名或连接到主机。
说白了就是http请求完成后的回调。代码创建了一个字典存了一下有关网络请求的信息,包括返回的值等self.mutableData 是在接收返回数据的代理中被赋值的,如果有错误信息则把错误抛回去(例如:code=1022,iOS9后不支持http请求等,xxx信息)。如果没有错误信息即认为是正确的。
这一句把返回的数据穿进去,其实就是兜一圈根据你的初始化解析报文体什么格式的数据就按照什么格式的解析,最后传回来。最后把返回的数据通过回调赶回去,这就是一个接收过程就完事啦。拼的字典最后通过通知传出去了,给需要的类,或者自己接收也行啊。如果不嫌麻烦的话🙃。
在下面就是对于下载数据的一些代理封装,怎么拼数据啥的,不多叙述
_AFURLSessionTaskSwizzling
这个类用到了runtime的高级api 替换函数,主要是替换Task 中的resume、suspend方法,加上通知,当此函数执行后可以发出通知告知业务类。借鉴网上的说法,这是一个神奇的类,为啥说神奇,不多说直接上代码 在load方法时就开始搞事情了。
![](https://img.haomeiwen.com/i2368622/95d1674af1ff1300.png)
到此AFURLSessionManager这个类就说的差不多,我这也只能窥其部分。不能窥其全貌啊,不过这个类算AFN的核心类了,其他的类都是为他服务的,一定要多看几遍。
AFURLResponseSerialization
这个类意在根据不同的返回体解析数据。所有的子类都需要实现AFURLResponseSerialization代理方法,这个代理有且只有一个这个方法。
![](https://img.haomeiwen.com/i2368622/1568939bbbec0c10.png)
在AFHTTPResponseSerializer类中init方法很简单 就是初始化了一个NSIndexSet。acceptableContentTypes参数为所每种响应格式所以解析的返回头中的信息
然后就是一个公共的验证响应有效性的方法啦
![](https://img.haomeiwen.com/i2368622/5d54a68b84bad6ab.png)
剩下的类目都是事先代理方法,根据不同数据格式进行解析,没啥好解释的啦,大家自己看啦。
AFHTTPRequestSerializer
这个类是拼装请求头,和请求体,具体的http协议的知识,如果不清楚的请看我推荐的书,我后面会发个链接供大家下载。
![](https://img.haomeiwen.com/i2368622/2c07556b79a7c06b.png)
初始化的时候默认使用UTF-8 拼接出来的信息都存在了mutableHTTPRequestHeaders字典中。其中HTTPMethodsEncodingParametersInURI初始化了通用拼装的请求类型 ,大家知道post是所以的信息是不会频道URL里的而是放到请求体里的。然后初始化了几个URLSession的参数.
allowsCellularAccess 会根据电量和电源灯情况自动设置最佳值
cachePolicy 设置缓存策略 NSURLRequestUseProtocolCachePolicy 对特定的 URL 请求使用网络协议中实现的缓存逻辑。这是默认的策略 使用默认的缓存策略,用kvo监听这几个值的变化,从而知道用户的需求,这种方法我觉得是不想暴露最核心的URLSession。
HTTPShouldHandleCookies 设置cookies
HTTPShouldUsePipelining 保证每个URLSession 都会开启一个单独的连接池
networkServiceType
timeoutInterval
在每次发起网络请求时都会调用此方法轻装请求头,这也算核心方法
![](https://img.haomeiwen.com/i2368622/99987b600e146b68.png)
中间的for循环是根据kvo获取到的值用kvc 的方式加载到NSMutableURLRequest中,设置属性,最后需要把保存到字典里的方法格式化橙http请求所用到的格式
![](https://img.haomeiwen.com/i2368622/29c5845401aa1799.png)
首先把已有格式转换成字典 如果parameters附带信息不为空,使用NSString * AFQueryStringFromParameters(NSDictionary *parameters)字典转出URL编码形式,URL编码就是一堆%的那种格式,不知道自己Google吧最后做个判断如果不是post形式的就把参数拼接到URL的后面 如果为post的就拼接到请求体中。
剩下的是拼装body 我也不是特别明白了,一般的情况下不需要,等我了解后把这部分补上,只能说我也学习不够啊,还在不断的看书中,
AFNetworkReachabilityManager
AFSecurityPolicy
这两个类我也不是特别懂了,都是用底层C语言去封装的,要是硬着头皮来需要看好久,我推荐大家看看大牛的讲解就好了,对于我这种渣渣来说实在是有心无力啊,不过还好这两个类都是单独的,不了解的话也不影响你对AFN核心业务的理解。
总结:其实看完AFN我还是感触颇多,之前对http不是很了解,逼着自己去看源码还是很起作用的,感觉受益良多,AFN除了主业务以外还有一些分类补充UIKit UIKit+AFNetworking 这个我会后续再写一篇,自私的说不为别人,为自己也得写一篇,我觉得把东西写出来后可以很好的补充一下当时被忽略的东西,很有用。
网友评论