iOS开发——AFNetworking源码(一)
简介
我们在学习AFNetworking之前,就必须知道AFNetworking是什么,具体有什么作用?
首先,AFNetworking是一个功能非常强大的框架,主要是用于网络请求,把复杂的原生代码封装好,我们只需要简单的几步就可以完成网络请求。
代码组成
从上图可以看出AFNetworking中含有很多类,那么这些类与类之间有什么关系呢,具体关系如图所示:
我们来解读一下这个图,按照我的理解来说,显而易见的是AFURLSessionManager应该是主力军,因为左边黄色框框里的四个类都是服务于AFURLSessionManager,举个例子,AFURLSessionManager如果是前方部队的话,其余四个就是他的后备军,所以只有AFURLSessionManager管理好这四个类,它才可以好好工作。(也就是说生成对应的sessionmanger,并且初始化并管理AFSecurityPolicy、AFNetworkReachabilityManager以及AFJSONResponseSerializer来一同为它所生成的sessionmanger服务)。
而AFHTTPSessionManager是继承于AFURLSessionManger的子类,内部管理自己的AFHTTPResponseSerializer和AFHTTPRequestSerializer两种序列化工具,用来对请求和响应的数据来做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;AFHTTPSessionManager本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;
模块划分
AFNetworking可以分成五个部分,具体如下:
- 网络通信模块(AFURLSessionManager、AFHTTPSessionManager)
- 网络状态监听模块(AFNetworkReachabilityManager)
- 网络通信安全策略模块(AFSecurityPolicy)
- 网络通信信息序列化模块(AFURLRequestSerialization,AFURLResponseSerialization)
- iOS UIkit库的拓展(UIKit)
我们可以看到AFNetWorking大致分为一下五大模块,其中最为核心的是网络通信模块,主要用来发送和响应请求;AFNetworkReachabilityManager主要是用来进行网络状态的监听,在不同网络状态下请求和响应的不同操作和处理;为了保证网络请求的安全性,当然少不了AFSecurityPolicy,网络安全策略模块,在初始化sessionmanger的时候同时初始化了AFSecurityPolicy以及网络通信信息请求序列化的类。网络通信信息序列化模块分为请求序列化和响应序列化,其内部分别会对请求头和响应头进行编码,在请求的时候,将请求头转码为计算机可识别的格式,在响应的时候将响应结果进行转码后传回给客户端。这几个模块息息相关,都是为一次HTTP请求的正常请求和响应做保障。最后一个模块就是基于UIKit库的一些相关拓展,其中包括UIImageView的请求,UIButton的请求等等。
AFNetworking使用流程
我们在使用AFNetworking进行网络请求的时候,首先需要生成对应的sessionManager,以我项目中的代码为例:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
我们要是直接看源码去学习关于上面的代码干了什么会有一些困难,所以我们可以先看一下下面的图解:
我们通过调用AFHTTPSessionManager的manager方法来进行初始化,那么在源码中manager方法实现了什么呢?
我们跳转到源码可以发现
由此可见,在AFHTTPSessionManager中的初始化方法最终都会调用其父类的initWitchSessionConfiguration初始化方法,返回一个sessionManager方法;那么,需要去看一下父类也就是AFURLSessionManager的初始化都做了什么:
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
//如果会话配置为nil的话,对应初始化一个
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
//初始化操作队列,并设置为串行队列 设置最大并发操作数
//1.⚠️
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
//AFJSONResponseSerializer用来序列化HTTP响应
self.responseSerializer = [AFJSONResponseSerializer serializer];
//初始化SSI所需要的AFSecurityPolicy用来保证请求的安全性
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
//AFNetworkReachabilityManager用来查看网络连接状态
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
//初始化可变任务字典task的id作为key,代理对象作为value
//2.⚠️
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
//初始化锁和锁的命名
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
//获取所有的task,设置一遍delegate用来异步的获取当前session的所有未完成的task,session和task的关系是一个session里有多个task
//初始化dataTasks一般为空,这里这么做的主要目的是为了防止从后台回来,重新初始化整个session,一些之前的后台请求任务,导致程序崩溃
//3.⚠️
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}
总结以下几点:
- 初始化当前的会话配置,操作队列,锁,AFNetworkReachabilityManager,AFSecurityPolicy,请求序列化以及用来存储任务的可变任务字典等属性;
- 获取当前session中所有未完成的task,给它们设置一遍代理;
这个函数有三个需要注意的点:
队列的最大并发操作数设置为1,这里的并发操作数值的是回调代理的线程并发数。
- self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];是用来将每一个请求任务和自定义的AFURLSessionManagerTaskDelegate来建立映射的;(需要深入研究,代理和这里的关系,以及利用KVO的思想实现的相关)
- 在初始化的时候获取当前session中的所有task,为它们重新设置一遍代理;一般来说初始化的session中的task应该是为空的,这里这么做的主要目的是为了防止从后台回来的时候初始化session,对于一些后台之前的请求任务没有重设代理导致崩溃的问题;这里里边不同的任务调用不同的addDelegateForXXX方法来设置代理,看一下这些方法的实现:
//为data任务添加代理
- (