一、AFN架构的最上层是AFHTTPSessionManager
AFHTTPSessionManager继承于AFURLSessionManager,它所做的主要工作是收集HTTP请求的URL、Parameters、成功的回调、失败的回调四个参数。然后自己的属性requestSerializer根据前两个参数URL和Parameter生成一个NSMutableURLRequest类的对象。然后把它交个父类处理,父类会返回一个NSURLSessionDataTask类的对象task,然后调用[task resume]
发起请求。
该过程对应的源码:
// AFHTTPSessionManager就是拿到这个方法产生的对象发起请求的
- (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;
// #1:URL&Parameters --> [requestSerializer] --> Request
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;
// #2:Request --> [AFURLSessionManager.session] --> DataTask
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;
}
二、AFN架构的核心类AFURLSessionManager
AFURLSessionManager就像一个“工厂”,NSURLSessionDelegate一系列代理方法就是“流水线”,task是“原料”,responseObject是产出的“产品”。#2这一流程就是由AFURLSessionManager完成的。
它的核心属性有
- sessionConfiguration:会话对象的配置信息类,默认使用的是default模式;
- session:会话对象,用于产生任务对象task;
- operationQueue:创建session会话对象的指定的队列,这是一个串行队列(最大并发数是1);
- responseSerializer:返回对象的序列化,主要负责状态判断、解析等任务;
- 四个xxxTasks数组:只读属性,存放的是请求任务;
- mutableTaskDelegatesKeyedByTaskIdentifier:以键值对的形式向task关联一些回调函数,key是taskIdentifier,value是回调组成的AFURLSessionManagerTaskDelegate类的对象;
- reachabilityManager:监管网络状态的对象;
- completionQueue:请求并解析完成后将在该队列中交付数据(调用请求的completionHandler),默认是主串行队列;
- completionGroup:交付数据(调用请求的completionHandler)时指定的任务组,AFN默认是一个静态的
dispatch_group_t
。该分组允许用户创建task1、task2...,当他们都完成时通过dispatch_group_notify()
再进行后续操作。
创建的静态对象有:
-
af_url_session_manager_creation_queue
:串行队列,将session创建task的任务交付到该队列;注:此队列是修复在iOS8.0之前并行创建task时得到的taskIdentifier异常的情况,iOS8.0系统已经修复了该bug。
-
af_url_session_manager_processing_queue
:专门对返回数据进行解析的队列。这是一个并行队列,能够更高效的完成数据解析任务; -
af_url_session_manager_completion_group
:将completionHandler归为该任务组,上述9中默认的静态任务组就是它。
#2流程细分:
step_1
:创建会话session,将会话的代理指定为自己(AFURLSessionManager有相当一部分代码是session对象的代理方法),创建串行队列,指定session回调在该队列中处理;
step_2
:根据Request创建任务task,同时创建AFURLSessionManagerTaskDelegate类的对象(它和task一一对应)。这个对象包含了Request对应的回调方法,它还有一个重要的任务就是存储和拼接服务器返回的数据,保存在mutableData中;
step_3
:根据task的标识taskIdentifier存储step_2
产生的对象,保存在字典中;
step_4
:当请求任务发起后,会有触发session的一系列代理方法,其中就附带了标识是哪个task的信息。当请求返回数据时根据task的taskIdentifier在step_3
产生的字典中找到对应的代理,让代理拼接数据;
step_5
:当请求完成时让任务的代理根据session的responseSerializer完成数据解析任务(该代理有一个对创建任务的会话的弱引用);
step_6
:执行completionHandler向外抛出数据。
核心代码:
- (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;
//step_2:生成task
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
//step_3:生成task关联的对象,将upload/downloadProgressBlock、completionHandler让关联对象管理
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
- (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
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;//反向的弱引用,指向存储自己的类
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];//用字典构建dataTask与delegate的对应关系
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
step_1
在NSURLSessionManager对象的初始化中完成。step_4
是一个“循环”,不断的产生数据,它以及step_5
、step_6
下文有详细描述。
三、NSURLSessionDelegate方法的执行以及后续任务的轮转
接收数据的代理方法
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}
[self delegateForTask:dataTask]
就是根据dataTask的任务标识找到与它对用的代理对象,代理对象将data拼接到mutableData中保存。
请求完成时的代理方法
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
请求完成后task的代理会对mutableData做异步的解析操作,[self removeDelegateForTask:task]
会移除与代理的一切通知,然后从字典中移除。
四、数据的解析和交付responseObject
先从源码看起:
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];//将NSMutableData拷贝以备解析之用
self.mutableData = nil;//释放内存空间
}
/* 构建通知的userInfo */
if (!error) {
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
/* 构建通知的userInfo */
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{// 交付数据
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{//发通知
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}
贴出的源码删去了构建通知userInfo和请求异常分支的处理流程(比成功时少了一个解析操作)。第一个dispatch_async()
包含了解析操作,解析完成后在主串行队列(解析完成后,用户拿到数据一般就要显示了)执行block把数据交付出去,然后在主队列发出任务完成的通知,通知的userInfo信息中AFNetworkingTaskDidCompleteSerializedResponseKey对应也是解析后的数据。
五、其他
5.1 关于AFURLSessionManagerTaskDelegate
它是NSURLSessionManager中的一个私有类,里面有两个关于上传和下载进度的属性:uploadProgress、downloadProgress,它通过把自己添加为对用task的观察者来实现自己的progress的值改变。
[task addObserver:self//自己(taskDelegate)将观察task的countOfBytesSent属性的变化情况
forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self//自己观察 进度(Progress)的“完成比例属性”的变化情况
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
// 当被观察对象是任务时,更新自己的progress值
if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
}
} else //当被观察对象是自己的progress时,执行上传下载的进度有更新的代理,并发进度以NSProgress对象的方式传递出去
if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
}
新数据下载/上传 --> task的属性发生变化 --> taskDelegate的progress同步该变化 --> progress的完成百分比就发生变化 --> taskDelegate发出通知
5.2 关系梳理:NSURLSessionManager、NSURLSession、AFURLSessionManagerTaskDelegate、NSURLSessionTask
持有1:属性持有;
持有2:通过集合属性持有;
持有3:虽然NSURLSession的.h文件没有给出存储它创建的task的集合属性,但有理由相信它也是采用持有2的形式存储的。
代理1:通过直接设置代理对象的方式实现;
代理2:通过key-value的方式建立联系,然后task有一些任务(数据拼接、进度管理)要处理的时候通过该联系找打taskDelegate,让它负责完成。
5.3获取Session创建的Task
方法:
- (void)getTasksWithCompletionHandler:(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler
,这是一个异步的方法,通过在Session的代理队列中执行回调的方式交付处理的结果。3个数组中包含的是有效的(未开始和进行中)task。大胆猜测一下它的实现:
- (void)getTasksWithCompletionHandler:(void (^)(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks))completionHandler {
dispatch_barrier_async(self.workQueue, ^{
NSMutableArray *dataTasks = [NSMutableArray array];
NSMutableArray *uploadTasks = [NSMutableArray array];
NSMutableArray *downloadTasks = [NSMutableArray array];
for (NSURLSessionTask *task in self.allTasks) {
if (task.state == NSURLSessionTaskStateRunning || task.state == NSURLSessionTaskStateSuspended) {
if ([task isKindOfClass:[NSURLSessionDataTask class]]) {
[dataTasks addObject:task];
} else if ([task isKindOfClass:[NSURLSessionUploadTask class]]) {
[uploadTasks addObject:task];
} else if ([task isKindOfClass:[NSURLSessionDownloadTask class]]) {
[downloadTasks addObject:task];
}
}
}
dispatch_async(self.delegateQueue, ^{
if (completionHandler) {
completionHandler(dataTasks, uploadTasks, downloadTasks);
}
})
})
}
当用户通过属性获取task的时候,NSURLSessionManager用了一个信号量,等待该异步操作操作的完成,然后返回给用户。
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
__block NSArray *tasks = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);//令牌数为0
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
tasks = dataTasks;
}/* 删减了其他分支 */
dispatch_semaphore_signal(semaphore);//放入一个令牌
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//令牌>0时向下执行,否者等待
return tasks;
}
六、总结
AFNetworking框架UIKit模块提供了View层的扩展,方便使用。Serialization模块负责请求和返回数据的序列化,Security模块负责网络安全,Reachability模块负责网络环境监测,NSURLSession模块将其他模块有机的组织在一起协同工作。