
AFNetworking 是 Objective-C 中用于网络请求的第三方框架,我们一般使用它来封装网络请求,这篇文章记录了阅读 AFNetworking(Version 3.1.0) 源码的笔记,简单的研究了它的实现细节。
前言
这里引用 @draveness 的一张图来展示 AFNetworking 的整个架构:

本系列以此架构为依据,随后的文章会逐一分析 AFNetworking 的实现原理。
流程
首先以官方 Demo 中的一个 Get 方法为例,来探究 AFNetworking 网络请求的大致流程。

- 1.Get 请求入口
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
- 2.创建 NSURLSessionDataTask
- (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
- 3.创建 NSURLSessionDataTask 前先创建 NSMutableURLRequest
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
- 4.用 request 创建 NSURLSessionDataTask
- (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
- 5.给 dataTask 添加 Delegate (主要为 task 提供进度管理功能)
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
以上方法是调用链上的主要方法,将在下文逐一解释。
1.Get 请求入口
具体方法体如下:
// 创建这个 NSURLSessionDataTask
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
/**
* session task的几种状态的操作函数
suspend -- 可以让当前的任务暂停
resume ---- 方法不仅可以启动任务,还可以唤醒suspend状态的任务
cancel ----- 方法可以取消当前的任务,你也可以向处于suspend状态的任务发送cancel消息,任务如果被取消便不能再恢复到之前的状态.
*/
[dataTask resume];
使用 GET 类型的 Request 来创建并运行一个 NSURLSessionDataTask,这里要注意的是用[dataTask resume]
来开启这个 task。
2.创建 NSURLSessionDataTask
主要方法体如下:
...
// 创建 NSMutableURLRequest
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
// 处理构建 request 产生的错误
...
// 创建 dataTask
__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;
dataTaskWithHTTPMethod:
这个函数的实现主要分两部分,一部分是构建NSMutableURLRequest,另一部分是根据已构建好的 Request 来创建 DataTask。
其中 Request 是由传递的 method 来创建,这里传递的是 GET,其它参数还有HEAD、POST、PUT、PATCH、DELETE 。
3.创建 NSMutableURLRequest
使用指定的 HTTP method 和 URLString 来构建一个 NSMutableURLRequest 对象实例,主要方法体如下:
// 参数断言
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
// 使用url构建并初始化NSMutableURLRequest,然后设置HTTPMethod
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
// 给NSMutableURLRequest自带的属性赋值
// 然后通过判断mutableObservedChangedKeyPaths(NSMutableSet)中是否有这个keyPath,来设定mutableRequest对应的keyPath值
// AFHTTPRequestSerializerObservedKeyPaths这个数组里的属性是固定的,且在 init 方法里全都 KVO 了
/**
* 当 AFHTTPRequestSerializerObserverContext 中有 value 变化了(且变化后的新值不为 NSNull null),就会响应 observerValueForKeyPath 这个函数,从而mutableObservedChangedKeyPaths就会添加这个 keyPath
*/
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
// 将传入的parameters进行编码,并添加到request中
/**
* 一般我们请求都会按key=value的方式带上各种参数,GET方法参数直接加在URL上,POST方法放在body上,NSURLRequest没有封装好这个参数的解析,只能我们自己拼好字符串。AFNetworking提供了接口,让参数可以是NSDictionary, NSArray, NSSet这些类型,再由内部解析成字符串后赋给NSURLRequest。
*/
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
如果 method 是 GET、HEAD、DELETE,那 parameter 将会被用来构建一个基于 url 编码的查询字符串(query url),并且这个字符串会直接加到request的url后面。对于 POST/PUT,它们会根据 parameterEncoding 属性进行编码,而后加到 request 的 http body 上。
4.用 request 创建 NSURLSessionDataTask
主要方法体如下:
__block NSURLSessionDataTask *dataTask = nil;
// 解决iOS8之前的一个bug
url_session_manager_create_task_safely(^{
// 用NSURLSession创建NSURLSessionDataTask
dataTask = [self.session dataTaskWithRequest:request];
});
...
用 NSURLSession 的 dataTaskWithRequest:
方法来创建 dataTask,这里需要注意的是方法被一个url_session_manager_create_task_safely
的 block 包起来,这里是为了解决 iOS 8 上的一个 bug。
5.给 dataTask 添加 Delegate
在这个方法里给 dataTask 添加了一个 AFURLSessionManagerTaskDelegate,并为 dataTask 提供进度管理功能,具体的是在[self setDelegate:delegate forTask:dataTask]
方法:
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 设置uploadProgress和downloadProgress这两个NSProgress变量
[delegate setupProgressForTask:task];
// 给session task添加KVO
[self addNotificationObserverForTask:task];
[self.lock unlock];
这里首先把task.taskIdentifier
作为 key,delegate
作为 value 存在一个 MutableDictionary 里,然后设置上传和下载两个 progress,并给 task 添加上启动和暂停的 KVO。
小结
通过这个流程可以初步了解 AFNetworking 内部方法调用关系,当然也可以看出其实 AFNetworking 就是对 NSURLSession 的高度地封装。随后的文章会结合源码,来深入理解 AFNetworking 的实现原理。
网友评论