一、NSURLSession部分
AFHTTPSessionManager继承自AFURLSessionManager类,主要是对AFURLSessionManager的封装。
这个类粗体分三部分也就是说有三部分功能:(1)初始化请求类,(2)开放一些请求类的属性(3)抽象出几种通常的http请求种类的方法。
(1)初始化请求类:
类方法返回一个AFHTTPSessionManager对象,可用于网络请求。
初始化方法,主要是对AFURLSessionManager初始化方法的封装,在对AFURLSessionManager的介绍中再详细解说。
(2)开放一些请求类的属性:
根URL
请求参数编码的序列化器,主要功能是将通常提交的字典参数根据不同的请求方式以及不同的数据提交格式序列化为相对应的字符串。
构造好之后将组装成具体请求方式相对应的结构,然后提交到传输层进行相对应的编码后,再交到会话层。
与requestSerializer相对应,将返回的结构依次反序列化得到期望的返回数据结构(字典,数组,字符串等)。
设置安全策略。
(3)抽象出几种通常的http请求种类的方法:
get类型相关方法:
参数URLString:NSString类型,用于构造请求URL
参数parameters:id类型(根据具体情况可能为字典、字符串、数组),将会根据设置的requestSerializer进行编码
参数success:nullable void(^)(NSURLSessionDataTask * task,id_Nullable responseObject的block对象,当请求任务成功执行后将被执行,responseObject为网络请求返回的参数根据设置的response serializer反编码后得到的期望的数据结构id类型(根据具体情况可能为字典、字符串、数组
参数failure:nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error)类型的block对象,当请求任务失败后将被执行,error会记录相关错误类型。
参数downloadProgress:nullable void(^)(NSProgress *downloadProgress)类型的block对象,当下载进度更新时会调用,在当前的会话队列中执行,不是在主队列中执行。
post类型相关方法:
参数URLString:NSString类型,用于构造请求URL
参数parameters:id类型(根据具体情况可能为字典、字符串、数组),将会根据设置的requestSerializer进行编码
参数success:nullable void(^)(NSURLSessionDataTask * task,id_Nullable responseObject的block对象,当请求任务成功执行后将被执行,responseObject为网络请求返回的参数根据设置的response serializer反编码后得到的期望的数据结构id类型(根据具体情况可能为字典、字符串、数组
参数failure:nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error)类型的block对象,当请求任务失败后将被执行,error会记录相关错误类型。
参数uploadProgress:nullable void(^)(NSProgress *uploadProgress)类型的block对象,当上传进度更新时会调用,在当前的会话队列中执行,不是在主队列中执行。
参数block:nullable void (^)(id <AFMultipartFormData> formData)类型block对象,多用图片或大文件的单个上传和批量上传。参见详情。 <AFMultipartFormData>可参见详情
head、patch、put、delete相关方法:
下面详细分析AFURLSessionManager类:
AFNetworking3.0采用了苹果新出的网络框架NSURLSession实现,仍使用NSOperation管理请求队列。
下面从一个调用开始分析,看看每一步都做了什么:
首先,要初始化:
先看看这个方法
其内容和平常的工厂方法没啥区别,也是调用一个传统的初始化方法:
再深入看
除了给对象本身baseURL、requestSerializer、responseSerializer赋初始值之外,主要来分析一下调用父类的初始化方法
前边部分主要是对NSSession请求方式做一个封装,再给自身相关属性赋值,比如网络安全策略,必要的锁等。
最后一个调用,意义可能是:为了防止后台回来,重新初始化这个session,一些之前的后台请求任务,导致程序的crash。参见详情
然后,就可以使用初始化好的AFHTTPSessionManager来做网络请求了:
下面从一个常用的post请求接口开始:
如图,先构造NSURLSessionDataTask *dataTask对象,然后调用[dataTask resume]方法发送请求。
下面具体分析这个构造方法:
使用请求参数序列化器self.requestSerializer根据传入的根路径、请求方法和参数构造NSMutableURLRequest对象。
如果构造失败,异步执行传入的failure。如果设置了self.completionQueue,则在这个队列中执行,否则在dispatch_get_main_queue()主队列中执行,这也是通常的场景。
紧接着根据之前构造的request对象以及传入的相关block对象构造dataTask,并根据请求失败或成功回调相应的block对象。
继续深入查看dataTask的构造方法:
查看这个方法,应该是解决iOS8之前的bug,鉴于现在大部分应用支持最低版本都在iOS8之后,不再深究这个方法。
这里通过系统方法通过初始化方法初始化的self.session构造dataTask。
下面重点分析
这个调用,这里也是AFNetworking中特别是NSURLSession部分最核心也最值得赞赏的部分:
下面逐行分析:
可以看出针对每一个dataTask都要创建一个AFURLSessionManagerTaskDelegate *delegate对象。
紧接着给相关属性赋值。
重要的一点:
这行代码将dataTask和相关的delegate对象关联起来,查看源码:
原来是是AFURLSessionManager维护了一个@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier的字典。
这个字典的每一个元素的key值是dataTask的taskIdentifier的标示,value则是关联的delegate对象。之前初始化方法中创建的self.lock对象用来保证线程安全。
添加了相关的监听。
纵上,dataTask就构造完整了,执行[dataTask resume]方法后将发起网络请求。
下边开始分析网络请求完成后是如何回调的:
从AFURLSessionManager声明中看出,AFURLSessionManager继承了NSURLSessionDelegate等相关协议,再查看self.session的初始化方法,以及dataTask的构造方法,可以看出,网络请求完成后是通过调用NSURLSessionDelegate的相关方法完成回调的。
由于这里分析的是dataTask是NSURLSessionDataTask对象,所以在完成请求后必然调用NSURLSessionTaskDelegate的以下方法:
和之前提到的
方法刚好相对应:
通过self.mutableTaskDelegatesKeyedByTaskIdentifier字典,根据dataTask的task.taskIdentifier的key值获取到之前关联的AFURLSessionManagerTaskDelegate *类型的delegate。
紧接着这里有点迷惑人的地方,作者没有为AFURLSessionManagerTaskDelegate独立设计一个方法,而是继承了NSURLSessionTaskDelegate协议,实现
这个协议方法对单独的dataTask进行回调处理。
下面继续分析这个方法:
通过delegate之前的赋值,获取到当前的AFURLSessionManager以及相关的responseSerializer反序列化器。
如果返回error不为空,如果设置了manager.completionGroup或manager.completionQueue相关队列,在其相关队列中,否则回到dispatch_get_main_queue()主队列中回调请求时设置的self.completionHandler的block对象。
如果error不为空,则调用
反序列化器manager.responseSerializer的解析方法获取到要返回的数据接着和上边相同,将结果回调。
最后,回到
这个最初的dataTask构造方法,在completionHandler中通过error是否为空,分别执行请求失败和成功的回调,也就是post请求入口设置的成功和失败回调:
结束之后,
在[self removeDelegateForTask:task]这里移除task的相关关联:
和之前的[self delegateForTask:task]和[self setDelegate:delegateforTask:dataTask]方法相对应。
就此一个post网络请求完成。
本篇主要是通过一个典型的post方法,梳理出AFNetworking框架中网络请求的主干流程,其他网络请求方式主干流程也大同小异,毕竟现在关于这个框架的博客文章数不胜数,优秀文章也比比皆是,所以我选择的角度就是通过一个网络请求流程将主干部分贯通,也就是对NSURLSession模块做一个梳理。后边将继续分析其他模块。