原文链接:http://itangqi.me/2016/05/06/the-notes-of-learning-afnetworking-two/
前言
首先,我们来看一下 AFNetworking 框架中主要涉及到了哪些类:
NSURLSession
AFURLSessionManager
AFHTTPSessionManager
序列化
AFURLRequestSerialization
AFURLResponseSerialization
附加功能
AFSecurityPolicy
AFNetworkReachabilityManager
下面,通过一张图来直观地感受下 AF 架构的设计:
AFHTTPSessionManager
AFHTTPSessionManager
is a subclass ofAFURLSessionManager
with convenience methods for making HTTP requests. When abaseURL
is provided, requests made with theGET
/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] // 负责序列化响应 |
从这个初始化方法的调用栈,我们可以非常清晰地了解这个框架的结构:
- 其中
AFURLSessionManager
是AFHTTPSessionManager
的父类 AFURLSessionManager
负责生成NSURLSession
的实例,管理AFSecurityPolicy
和AFNetworkReachabilityManager
,来保证请求的安全和查看网络连接情况,它有一个AFJSONResponseSerializer
的实例来序列化 HTTP 响应AFHTTPSessionManager
有着自己的AFHTTPRequestSerializer
和AFJSONResponseSerializer
来管理请求和响应的序列化,同时依赖父类提供的接口保证安全、监控网络状态,实现发出 HTTP 请求这一核心功能
baseURL
关于 baseURL
一开始我是有点迷糊的,不过源代码中有如下注释:
For HTTP convenience methods, the request serializer constructs URLs from the path relative to the
-baseURL
, usingNSURL +URLWithString:relativeToURL:
, when provided. IfbaseURL
isnil
,path
needs to resolve to a validNSURL
object usingNSURL +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)),我是在浏览相关文章时发现这个问题的,所以在此提及一下:
- AFHTTPSessionManager subclass not deallocating - retain cycle?
- AFHTTPSessionManager and AFURLSessionManager never deallocated
- block retain cycle in AFUrLSessionManager init method