AFNetworking 是 Objective-C 中用于网络请求的第三方框架,我们一般使用它来封装网络请求,这篇文章记录了阅读 AFNetworking(Version 3.1.0) 源码的笔记,简单的研究了它的实现细节。
前言
这里引用 @draveness 的一张图来展示 AFNetworking 的整个架构:
本系列以此架构为依据,随后的文章会逐一分析 AFNetworking 的实现原理。
流程
首先以官方 Demo 中的一个 Get 方法为例,来探究 AFNetworking 网络请求的大致流程。
1 2 3 4
| - (NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
- 2.创建 NSURLSessionDataTask
1 2 3 4 5 6 7
| - (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
1 2 3 4
| - (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters error:(NSError *__autoreleasing *)error
|
- 4.用 request 创建 NSURLSessionDataTask
1 2 3 4
| - (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 提供进度管理功能)
1 2 3 4
| - (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 请求入口
具体方法体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // 创建这个 NSURLSessionDataTask NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod: 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
主要方法体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ... NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; ... __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 对象实例,主要方法体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| // 参数断言 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
主要方法体如下:
1 2 3 4 5 6 7
| __block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{ 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]
方法:
1 2 3 4 5 6 7 8 9 10
| NSParameterAssert(task); NSParameterAssert(delegate);
[self.lock lock]; self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate; [delegate setupProgressForTask:task]; [self addNotificationObserverForTask:task]; [self.lock unlock];
|
这里首先把task.taskIdentifier
作为 key,delegate
作为 value 存在一个 MutableDictionary 里,然后设置上传和下载两个 progress,并给 task 添加上启动和暂停的 KVO。
小结
通过这个流程可以初步了解 AFNetworking 内部方法调用关系,当然也可以看出其实 AFNetworking 就是对 NSURLSession 的高度地封装。随后的文章会结合源码,来深入理解 AFNetworking 的实现原理。