AFNetworking 3.0 源码阅读笔记(二)

前言

首先,我们来看一下 AFNetworking 框架中主要涉及到了哪些类:

NSURLSession

  • AFURLSessionManager
  • AFHTTPSessionManager

序列化

  • AFURLRequestSerialization
  • AFURLResponseSerialization

附加功能

  • AFSecurityPolicy
  • AFNetworkReachabilityManager

下面,通过一张图来直观地感受下 AF 架构的设计:


AFHTTPSessionManager

AFHTTPSessionManager is a subclass of AFURLSessionManager with convenience methods for making HTTP requests. When a baseURL is provided, requests made with the GET / POST / et al. convenience methods can be made with relative paths.

一句话总结:AFHTTPSessionManager 继承于 AFURLSessionManager,并提供了方便的 HTTP 请求方法。

下面,我们通过一段实际代码来感受下:

1
2
3
4
5
6
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.app.net/"]];
[sessionManager GET:@"stream/0/posts/stream/global" parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
NSLog(@"请求成功---%@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"请求失败---%@", error);
}];

通过上面短短几行代码,我们便完成了 GET 请求,有木有很简单!现在是不是很想知道其背后蕴藏的玄机呢?别急,下面就让我们一起来探一探究竟。


调用栈

initWithBaseURL:

首先,我们来探一探 AFHTTPSessionManager 初始化方法 - initWithBaseURL: 的调用栈:

1
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.app.net/"]];

我们一路「Command + 左键」,可以归纳出如下结果:

1
2
3
4
5
6
7
8
9
- [AFHTTPSessionManager initWithBaseURL:]
- [AFHTTPSessionManager initWithBaseURL:sessionConfiguration:]
- [AFURLSessionManager initWithSessionConfiguration:]
- [NSURLSession sessionWithConfiguration:delegate:delegateQueue:]
- [AFJSONResponseSerializer serializer] // 负责序列化响应
- [AFSecurityPolicy defaultPolicy] // 负责身份认证
- [AFNetworkReachabilityManager sharedManager] // 查看网络连接情况
- [AFHTTPRequestSerializer serializer] // 负责序列化请求
- [AFJSONResponseSerializer serializer] // 负责序列化响应

从这个初始化方法的调用栈,我们可以非常清晰地了解这个框架的结构:

  • 其中 AFURLSessionManagerAFHTTPSessionManager 的父类
  • AFURLSessionManager 负责生成 NSURLSession 的实例,管理 AFSecurityPolicyAFNetworkReachabilityManager,来保证请求的安全和查看网络连接情况,它有一个 AFJSONResponseSerializer 的实例来序列化 HTTP 响应
  • AFHTTPSessionManager 有着自己的 AFHTTPRequestSerializerAFJSONResponseSerializer 来管理请求和响应的序列化,同时依赖父类提供的接口保证安全、监控网络状态,实现发出 HTTP 请求这一核心功能

baseURL

关于 baseURL 一开始我是有点迷糊的,不过源代码中有如下注释:

For HTTP convenience methods, the request serializer constructs URLs from the path relative to the -baseURL, using NSURL +URLWithString:relativeToURL:, when provided. If baseURL is nil, path needs to resolve to a valid NSURL object using NSURL +URLWithString:.

并举例进行了说明:

1
2
3
4
5
6
7
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/

所以,baseURL 为访问的基路径如:https://api.app.net/, path 是跟在基路径之后的部分路径,如:stream/0/posts/stream/global(因为 AFNetworking 的访问方式才这样划分)。

GET:parameters:process:success:failure:

初始化方法很好地揭示了 AFNetworking 整个框架的架构,接下来我们要通过分析另一个方法 - GET:parameters:process:success:failure: 的调用栈,看一下 HTTP 请求是如何发出的:

1
2
3
4
5
6
7
8
9
- [AFHTTPSessionManager GET:parameters:process:success:failure:]
- [AFHTTPSessionManager dataTaskWithHTTPMethod:parameters:uploadProgress:downloadProgress:success:failure:] // 返回 NSURLSessionDataTask #1
- [AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:] // 返回 NSMutableURLRequest
- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] // 返回 NSURLSessionDataTask #2
- [NSURLSession dataTaskWithRequest:] // 返回 NSURLSessionDataTask #3
- [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:]
- [AFURLSessionManagerTaskDelegate init]
- [AFURLSessionManager setDelegate:forTask:]
- [NSURLSessionDataTask resume]

在这里 #1 #2 #3 处返回的是同一个 data task,我们可以看到,在 #3 处调用的方法 - [NSURLSession dataTaskWithRequest:] 和只使用 NSURLSession 发出 HTTP 请求时调用的方法 - [NSURLSession dataTaskWithRequest:completionHandler:] 差不多。在这个地方返回 data task 之后,我们再调用 - resume 方法执行请求,并在某些事件执行时通知代理 AFURLSessionManagerTaskDelegate

我们在第一篇文章中已经说明过,AFNetworking 3.0 既是在 NSURLSession 之上的高度封装,并提供更加简洁易用的 API。从调用栈的结果来看,将使我们的理解更加清晰。


循环引用

关于在使用 AFNetworking 的过程中出现循环引用的问题,我并没有在实际开发中遇到过(其实我丫的根本就没写过几行代码好嘛( TДT)),我是在浏览相关文章时发现这个问题的,所以在此提及一下:


参考