AFNetWorking源码学习(一)——简述

3,143 阅读11分钟

        目前工作中进行网络请求都是用我们内部封装好的网络库,也未曾了解过真正请求的整个流程,借此学习AFNetworking源码的机会,一来对于网络请求每个节点做了哪些事情,为什么要做这么做进行一个熟悉和掌握,看看AFNetworking是如何实现的;二来学习AFNetworking的实现方式以及优秀的代码等;

        本文结束,将回答以下问题:  

  • 原生的方式是如何发送一个网络请求的?
  • AFNetworking中都有哪些模块,作用是什么?
  • 每个模块类之间的关系是什么?    
  • 利用 AFNetworking是如何来发送一个网络请求的?

一、原生的网络请求发送方式

这里只针对NSURLSession,不去研究在这之前的NSURLConnection,分别以GET和POST两种请求方式来进行使用:

1、GET请求方式

步骤:

  • 确定请求的路径URL
  • 创建可变的请求对象request:可省略((默认包含了请求头和请求方法【Get】),此步骤可以省略)
  • 创建会话session对象
  • 根据会话对象创建请求任务datatask,(利用dataTaskWithRequest或者dataTaskWithURL方法来进行创建)
  • 执行Task
  • 当得到服务器返回的响应后,解析数据(XML、JSON、HTTP)如果返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理

2、POST请求

步骤:

  • 确定请求的路径URL
  • 创建可变的请求对象request:不可省略——POST请求需要设置请求头
  • 设置请求头(需要对创建好的请求头进行序列化:确保为服务端可识别的数据格式)和请求方式POST
  • 创建会话session对象
  • 根据会话对象创建请求任务datatask——(通过dataTaskWithRequest)
  • 执行Task
  • 当得到服务器返回的响应后,解析数据(XML、JSON、HTTP)如果返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理

(这里的数据都是假数据,主要是为了表达post请求方式需要传参,参数序列化等)

这样发现,用原生的请求方式也能完成网络请求,那么为什么要有AFNetworking的存在呢 ,这里就需要对比以下两者的优缺点了,准确的来说应该是AFNetworking的优势所在了,这点在完成整个学习之后给出答案;

二、AFNetworking

1、代码结构

目前所使用的是AFNetworking4.0的版本,结构上没有之前分明,但是基本的结构也是没变的。类与类之间的关系如下图所示:

        自己的理解:AFURLSessionManger是主力军,它会在最前方输出,有很多的辅助兵,他要管理好这些辅助,这些辅助才能够在它需要的时候提供能力,以此来确保整场“战役”的胜利。(也就是说生成对应的sessionmanger,并且初始化并管理AFSecurityPolicy、AFNetworkReachabilityManager以及AFJSONResponseSerializer来一同为它所生成的sessionmanger服务)。

而AFHTTPSessionManager是AFURLSessionManger的子类,内部管理自己的AFHTTPResponseSerializer和AFHTTPRequestSerializer两种序列化工具,用来对请求和响应的数据来做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;AFHTTPSessionManager本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;

前方出场的是父子,而后方给予支援的就是我们的网络监控模块,安全策略模块以及序列化工具模块等;

2、模块划分

        AFNetWorking大致分为一下五大模块,其中最为核心的是网络通信模块,主要用来发送和响应请求;AFNetworkReachabilityManager主要是用来进行网络状态的监听,在不同网络状态下请求和响应的不同操作和处理;为了保证网络请求的安全性,当然少不了AFSecurityPolicy,网络安全策略模块,在初始化sessionmanger的时候同时初始化了AFSecurityPolicy以及网络通信信息请求序列化的类。网络通信信息序列化模块分为请求序列化和响应序列化,其内部分别会对请求头和响应头进行编码,在请求的时候,将请求头转码为计算机可识别的格式,在响应的时候将响应结果进行转码后传回给客户端。这几个模块息息相关,都是为一次HTTP请求的正常请求和响应做保障。最后一个模块就是基于UIKit库的一些相关拓展,其中包括UIImageView的请求,UIButton的请求等等。

  • 网络通信模块(AFURLSessionManager、AFHTTPSessionManager)
  • 网络状态监听模块(AFNetworkReachabilityManager)
  • 网络通信安全策略模块(AFSecurityPolicy)
  • 网络通信信息序列化模块(AFURLRequestSerialization,AFURLResponseSerialization)
  • iOS UIkit库的拓展(UIKit)

3、使用流程

以GET请求为例,以下是请求的代码,步骤:

  • 生成对应的sessionManager;

  • 调用GET方法进行请求;

  • 在GET回调里边处理结果,包括(任务进度,请求成功的结果,请求失败的结果);

    AFHTTPSessionManager *sessionManager =[AFHTTPSessionManager manager];    // parameters 参数字典 
    [sessionManager GET:@"https://www.baidu.com" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {        //进度
     } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {        // task 我们可以通过task拿到响应头        // responseObject:请求成功返回的响应结果(AFN内部已经把响应体转换为OC对象,通常是字典或数组)     } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // error 错误信息      }];
    

        这短短几行代码,进入源码,看看AFNetworking内部为我们做了些什么,以下是整个流程图解;

(1)蓝色部分是针对**AFHTTPSessionManager *sessionManager =[AFHTTPSessionManager manager];**这一行代码进行的图解,根据图解我们一起来看源码:

        首先是通过调用AFHTTPSessionManager的manager方发来进行初始化,那么来看一下manager方法:

        由此可见,在AFHTTPSessionManager中的初始化方法最终都会调用其父类的initWitchSessionConfiguration初始化方法,返回一个sessionManager方法;那么,需要去看一下父类也就是AFURLSessionManager的初始化都做了什么:

  • 初始化当前的会话配置,操作队列,锁,AFNetworkReachabilityManager,AFSecurityPolicy,请求序列化以及用来存储任务的可变任务字典等属性;
  • 获取当前session中所有未完成的task,给它们设置一遍代理;

这个方法中需要注意的地方有三点,如果图中⚠️所示:

  1. ⚠️⚠️⚠️队列的最大并发操作数设置为1,这里的并发操作数值的是回调代理的线程并发数。
  2. ⚠️⚠️⚠️self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];是用来将每一个请求任务和自定义的AFURLSessionManagerTaskDelegate来建立映射的;(需要深入研究,代理和这里的关系,以及利用KVO的思想实现的相关)
  3. ⚠️⚠️⚠️在初始化的时候获取当前session中的所有task,为它们重新设置一遍代理;一般来说初始化的session中的task应该是为空的,这里这么做的主要目的是为了防止从后台回来的时候初始化session,对于一些后台之前的请求任务没有重设代理导致崩溃的问题;这里里边不同的任务调用不同的addDelegateForXXX方法来设置代理,看一下这些方法的实现:

        这三个方法都是为不同的任务设置代理,最终都会调用setDelegate设置代理并存储datatask任务;

        这个方法主要是把代理和task建立映射关系,并且存储到事先声明好的字典当中;同时为当前task添加监听;在添加监听的方法中,taskDidResume和taskDidSuspend为接收到通知后的处理方法;用来恢复任务和暂停任务;至此,对于初始化的时候获取当前session中的所有task,已经为它们重新设置一遍代理。回到initWitchSessionConfiguration方法中返回当前对象,向上返回,生成AFHTTPSessionManager *sessionManger对象;

(2)接下来,利用生成的sessionManager发起请求:来看看****sessionManager调用GET方法都做了哪些事,以下是图解流程,然后对比源码层面进行分析:

先看看GET方法内部做了什么:

GET方法内部一是生成datatask,二是开启请求;

        生成datatask进入到AFHTTPSessionManager中的da taTaskWithHTTPMethod方法,进去看看:

1、🤗️🤗️🤗️调用请求序列化类中的requestWithMethod方法进行序列化处理

通过requestSerializer来调用requestWithMethod对请求参数进行序列化,最终生成一个最终请求网络需要的request实例;这里提出一个问题:为什么要进行序列化?那这里,先看看requestWithMethod方法内部都做了些什么:

在requestWitchMethod方法中,做了三件事情:

  • 创建mutableRequest并设置其请求方法;
  • 把当前类设置的一些属性设置给mutableRequest;(存在疑问)
  • 把需要传递的参数进行编码并且设置到mutableRequest当中;

看看编码的方法:

  • 从当前请求队列中拿到self.HTTPRequestHeaders中拿到设置的参数,赋值要请求的request中;(疑问点)
  • 把网络请求的参数转换为NSString类型,这一步是对参数进行转码;
  • 将请求方法拼接到url中;GET、HEAD、DELETE这几个method的quey是拼接到url后面的。而POST、PUT是把query拼接到http body中的;

        以下这几个方法就是我们在转码的时候所使用的方法,如何将请求参数进行转码:也就是通过递归调用并解析,直到解析的除了array,dic,set以外的元素,然后将最终得到的参数返回;

(ps:红色箭头为返回路径,黄色箭头为调用路径)

        到这里序列化的 部分结束,返回一个NSMutableURLRequest实例;紧接着设置请求头并且通过回调处理序列化失败的情况;

🙋🙋🙋回答:为什么要进行序列化?

在HTTp网络请求是基于字节流的网络传输,序列化是可以将一个对象转化成一段字节编码,以此方便在网络上传输或者做其他存储处理,使用的时候在对其做反序列化;简单的来说就是为了统一,我们可以用自己的方法来保存对象,但是在底层只提供一种保存对象状态的机制。因此我们在存储的时候需要进行序列化,以此来和提供的保持一致,在读取的时候对其进行反序列化,得到我们想要的形式;

2、🤗️🤗️🤗️调用dataTaskWithRequest来生成一个datatask任务

        在调用的时候,将序列化后的request,等参数传入,先看看dataTaskWithRequest方法里边做了什么事情吧:

        可以看到,生成一个datatask,并且调用addDelegateForXXX方法来设置代理,那么,设置代理这一块,和在初始化的时候为当前初始化session中的task设置代理的过程是一样的。(向上👆查看初始设置代理部分);

        最终返回一个dataTask任务,创建完成之后通过回调返回进度以及comple情况,在dataTaskWithHTTPMethod方法中进行处理;这里回到dataTaskWithHTTPMethod方法中,做完上述处理之后,最终将生成的dataTask返回到GET方法当中,这样最终在GET中就拿到了我们可以发送请求的task,最后调用系统方法[dataTask resume**];发起网络请求;**

当然,在GET方法中有progress,success**,**failure回调,使用的时候直接根据回调来处理不同情况,不用像原生的方法那样,进行多次判断,确认哪一种情况,再去做处理;

回到我们的初始化方法,在调用AFURLSessionManager的initWithSessionConfiguration方法初始化一个sessionManager的时候,在进行懒加载的时候,初始化session:

        由此看到,在初始化session的时候,将AFURLSessionManager作为了所有task的delegate。因此当我们进行网络请求的时候,这些代理就会被执行。AFURLSessionManager遵守的代理包括:NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying;下文具体来讲解AFURLSessionManager以及他的代理等;

        小结:

本文到此,我们对AFNetworking也有了大致的认识,可以回答文章开头所提出的问题了;清晰了结构,了解了使用,那从下文开始从最核心的网络通讯模块开始依此介绍每个模块的功能介绍,包含哪些内容、源码分析;多指教。

ps:学习过程有参考网上对于AFNetworking源码的解析学习帖子;