从一次请求开始
AFNetworking 建立在 iOS 7 引入的 NSURLSession 之上。理解它,最有效的入口不是一次读完所有源码,而是沿着一条请求,看看这层封装到底承担了哪些职责。本文对应 3.2.1 版本。
先看对象之间的关系
AFURLSessionManager 管理 Session;AFHTTPSessionManager 构造 HTTP 请求;序列化、安全策略和网络可达性各自独立。
AFHTTPSessionManager 继承 AFURLSessionManager。前者提供面向 HTTP 的接口,后者负责 Session 和 Task 的管理;请求序列化、响应序列化、可达性与安全策略则由周边对象协作完成。
日常调用通常只需要 AFHTTPSessionManager 的公开接口。需要改造库或设计自己的网络层时,再深入这条调用链,会更容易把握边界。
GET 请求如何变成 Task
先创建 manager,配置序列化器,再调用 GET:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = 10;
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain", nil];
[manager GET:@"https://example.com/api/discovery" parameters:@{@"name": @"kelvin"} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"%@", task);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@", error);
}];
示例设置十秒超时和允许的响应 Content-Type。公开 API 接收 URL、参数、进度、成功与失败回调。
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
[dataTask resume];
return dataTask;
}
GET 通过 dataTaskWithHTTPMethod:... 创建数据任务,启动后把任务返回给调用方,便于后续取消或观察。
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
这一层首先让请求序列化器生成 NSMutableURLRequest。序列化失败时,会把失败回调派发到配置的 completion queue;没有配置时使用主队列。成功后创建数据任务,将底层 completion handler 转换为公开 API 的成功与失败回调。
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler
{
__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
执行进入 AFURLSessionManager。HTTP manager 已经完成请求构造和序列化,这里接手 Task 的创建和管理。url_session_manager_create_task_safely 内部调用 Foundation API:
/* Creates a data task with the given request. The request may have a body stream. */
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
随后 addDelegateForDataTask:... 为任务关联一个 AFURLSessionManagerTaskDelegate。它参与 Task、Data 与 Download 的代理协议:
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
任务代理以当前 Task 初始化:
- (instancetype)initWithTask:(NSURLSessionTask *)task;
这个对象收集单个任务的状态,将代理事件转换成进度和完成回调。Session 级管理与每个 Task 的局部状态由此分开。
HTTP manager 序列化请求,Session manager 创建任务和代理,完成事件再沿接口返回。
应用网络层应该放在哪里
不必为每个请求都创建 manager。长期存在的 client 可以复用 Session,让系统按自身策略复用连接。应用层统一持有 manager,也更容易集中管理认证、日志与请求策略。
但有一个常见误区:AFURLSessionManager.operationQueue 是 Session 的代理回调队列。改变它的并发数,影响的是回调交付,不是网络任务的在途数量。
传输配置应在创建 manager 时通过 NSURLSessionConfiguration 传入。例如 HTTPMaximumConnectionsPerHost 控制单个主机的连接数;在 HTTP/2 多路复用下,连接数又不等于请求数:
NSURLSessionConfiguration *configuration =
[NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPMaximumConnectionsPerHost = 4;
AFHTTPSessionManager *manager =
[[AFHTTPSessionManager alloc]
initWithSessionConfiguration:configuration];
如果产品要求“整个应用最多同时执行四个 API 操作”,应该在 AFNetworking 之上建立应用自己的调度器,决定何时创建或启动任务。底层的 socket、连接复用和协议行为仍交给 URL Loading System。
AFNetworking 没有替代 Apple 的网络栈。它把请求构造、序列化、任务代理、进度和完成回调组织成了更一致的接口。设计上层封装时,先区分这些职责,通常比继续叠加工具方法更有价值。