本篇是 AFNetworking 源码解读的第一篇。主要来了解如何通过 AFNetworking 发送网络请求
AFHTTPSessionManager
我们在写需求的时候很少碰到直接使用 NSURLSession
的情况,都是使用 AFHTTPSessionManager
的封装(虽然我们一般还要再封装一层)。
AFHTTPSessionManager
是 AFURLSessionManager
的子类,属于对外调用的接口,承担了小部分的功能,主要实现还是在 AFURLSessionManager
中
初始化
AFHTTPSessionManager
的初始化方法最终来到这里:
1 | - (instancetype)initWithBaseURL:(NSURL *)url |
参数接收一个 NSURLSessionConfiguration
实例,它是创建 NSURLSession
需要的配置项。同时它保存了 baseURL
,并且创建了请求和响应序列化对象 requestSerializer
和 responseSerializer
。
几个 set 方法
初始化的时候,创建了默认的 AFHTTPRequestSerializer
和 AFJSONResponseSerializer
。如果有特殊的 content-type 的请求或者相应,那么就需要定义序列化对象,因此提供了两个 set 方法,分别设置请求和响应序列化对象。
还有一个关于安全策略的 set 方法,用来设置 HTTPS 下,证书的校验策略。
1 |
|
语义化请求方法
AFN 提供了进行不同方式请求的方法封装,这里进列举 get 和 post 两个方法:
1 | /// get 的正真方法带有 progress 参数 |
他们调用了另一个方法后,就生成了一个 NSURLSessionDataTask
实例对象,并且通过 resume
方法开启网络请求。
那么创建 NSURLSessionDataTask
的方法做了什么呢?
1 | /// 不带 constructingBodyWithBlock 创建 NSURLSessionDataTask |
首先通过前面的请求序列化类创建一个 NSMutableURLRequest
然后使用它创建 NSURLSessionDataTask
,不过创建方法不在本类中,而是在它的父类中。这个将稍后再看。
可以看到,在经过一系列的封装之后,发送一个网络请求需要的 NSMutableURLRequest
,NSURLSession
,NSURLSessionDataTask
都通过 AFN 创建了,而自己只需要负责传入请求,参数和回调即可。
发送 form-data 请求
上面的 get,post 方法无法发送文件,因此,AFN 提供了一个方法用来发送 form-data 类型的请求:
1 | /// post 方法带 constructingBodyWithBlock 的 |
该方法会发起一个 form-data 类型的请求。你可以将 NSData
放入 param 中,由 AFN 进行序列化。也可以拿到 constructingBodyWithBlock
中的 block,通过 AFMultipartFormData
协议的方法,向其中添加 fileURL,来告诉 AFN 去序列化该地址下的文件。
AFURLSessionManager
AFURLSessionManager
是 AFN 请求的核心。它遵循了下面几个协议:
- NSURLSessionTaskDelegate
- NSURLSessionDataDelegate
- NSURLSessionDownloadDelegate
- NSURLSessionDelegate
AFURLSessionManager 的属性
AFURLSessionManager
中包含了非常多的实现协议时自定义的 block:
1 | @interface AFURLSessionManager () |
AFURLSessionManager 的方法
初始化方法
初始化方法中创建了请求需要使用的各种基本属性:
1 |
|
创建 Task
创建的 Task 分为三种,普通的 dataTask,上传的 uploadTask 和下载的 downloadTask。
dataTask
在 AFHTTPSessionManager
中已经创建好了 NSURLRequest
对象,调用以下方法创建 NSURLSessionDataTask
对象实例:
1 | - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request |
除了简单调用 NSURLSession
的 API 生成实例外,AFURLSessionManager
还需要给生成的 dataTask 创建一个代理对象。这个下面就会说到。
uploadTask
uploadTask 在 AFHTTPSessionManager
中没有使用,AFHTTPSessionManger
提供的方法中要想实现上传功能,需要自己把文件转为 NSData 后通过参数上传。而 uploadTask 是自己通过输入流的方式将数据写入到了 request 中。使用 uploadTask 则能更加方便的交由 NSURLSession
完成相应的任务。只需要传入文件路径,data,或者输入流即可:
1 |
|
同样的,每一个 dataTask 都会设置一个 delegate。
downloadTask
downloadTask 分为两个部分,一个是创建,一个是断线续传:
1 |
|
如果你不熟悉 NSURLSessionDownloadTask
那么你一定会很疑惑下面这个继续下载为什么只要传一个 resumeData
就可以知道下载的所有信息的。其实这个 resumeData
并不是下载的数据,而是下载数据的信息的 plist 生成的 NSData
,其中包含了下载所需要的各种信息,包括本地缓存的路径名,下载的地址,当前下载了多少等。
为 task 创建代理
task 请求过程中的请求中请求完成的回调都是通过 delegate 完成的。delegate 是一个 AFURLSessionManagerTaskDelegate
实例。添加代理的过程就是创建实例并设置回调方法的过程:
1 | /// 设置 task 的代理; 代理包含了 task 的各种回调。 |
每一个生成的 task 和它的代理都会保存在 manager 的 mutableTaskDelegatesKeyedByTaskIdentifier
中。当然其实也可以通过给 task 添加关联对象的方式保存 delegate。
协议方法
上面说到了 AFURLSessionManager
实现了 NSURLSession
相关的四个代理。下面来分别看看:
NSURLSessionDelegate
如果有相关的 block 那么就执行相关的 block,没有 block 也可以通过监听相应的 notification :
1 | /// 因为异常终止请求 |
NSURLSessionTaskDelegate
1 | /// 重定向操作 |
在发送请求的时候,将请求的总数据和已发送的数据通过 delegate 的相应方法保存下来:
1 | /// AFURLSessionManagerTaskDelegate 中 |
在请求完成时,又调用了 delegate 的相应方法:
1 | /// AFURLSessionManagerTaskDelegate 中 |
这里 AFN 除了调用回调以及发送通知外,我们还可以发现使用了 dispatch_group_async
。它可以帮助我们做一些多个请求同步的操作。url_session_manager_completion_group()
方法提供了一个 group:
1 | static dispatch_group_t url_session_manager_completion_group() { |
我们可以在外部通过 AFN 发起多个请求,然后通过 url_session_manager_completion_group()
方法提供的 group,在请求完成后统一执行。当然其实我们亦可以在各个请求的完成回调中通过信号量的方式执行。不过那样就有点不是那么优雅了。
NSURLSessionDataDelegate
1 |
|
主要关系受到数据后的回调方法,它把接收到的 data 传给了 delegate:
1 | /// AFURLSessionManagerTaskDelegate 中 |
前面请求完成时传给 responseSerializer
的就是这里 mutableData
拼接好的数据。它把每次收到的数据都拼接起来,等待请求完成。
NSURLSessionDownloadDelegate
1 |
|
NSURLSession
中的下载由系统自动做了边下边存的过程。因此,我们要在下载完成之后把缓存的路径上的文件保存到实际的路径上。所以下载的时候要给 manager 传入一个 downloadTaskDidFinishDownloading
的 block,告知下载完成时候安放的路径。
总结
AFHTTPSessionManager
和 AFURLSessionManager
是我们使用 AFN 的入口。AFHTTPSessionManager
作为子类,封装了简单 dataTask 请求。它还负责将请求参数拼接以及转码。
对于上传文件的操作,仍然可以使用 AFHTTPSessionManager
创建 content-type 为 form-data 的请求,但是这就需要自己把文件转为 NSData
或者 NSInputStream
类型,设置给 request。如果想要更方便的方式完成,可以使用 AFURLSessionManager
提供的 upload 方法创建的 uploadTask,只需要给出 fileURL 即可。
AFURLSessionManager
负责创建 NSURLSession
,并承担了发送请求需要实现的所有协议。针对每一个 task,为其增加一个代理对象。当 AFURLSessionManager
接收到NSURLSessionDataDelegate
的接收 data 的回调的时候,就会把 data 交给 task 对应的 delegate 保存。当接收到 NSURLSessionTaskDelegate
的完成回调的时候,就会告知 task 对应 delegate,让其执行回调方法。
同时 AFURLSessionManager
实现的 NSURLSessionDelegate
还包含了 HTTPS 证书校验的策略,通过它验证证书信息。