概述
AFNetworking3.x 其实是对 NSUrlSession 的封装;
-
AFNetworking 总共分为 5 个模块:
- 通信模块 AFHTTPSessionManager, AFURLSessionManager ;
- 网络检测模块 AFNetworkReachabilityManager ;
- 网络安全https模块 AFSecurityPolicy ;
- 序列化和反序列化模块 Serialization ;
- ui组件封装模块 ;
AFHTTPSessionManager *manage = [[AFHTTPSessionManager alloc] init];
[manage GET:@"http://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
解析通信模块
AFHTTPSessionManager 是 AFURLSessionManager 子类,提供给外界使用的网路请求类;
AFHTTPSessionManager在初始化时, 设置了默认的序列对象为AFHTTPRequestSerializer,反序列化对象为AFJSONResponseSerializer,并且调用父类的初始化方法;
在父类的初始化方法中,创建了一个队列,并发量为 1,是为了保证请求在回调时,串行执行,防止数据错落;但为何不设置并发量为n,然后回调时用NSLock来防止数据错乱问题呢?
使用NSLock来锁住、解锁,会增加等待加锁和解锁时间,并且开销额外的线程开支,所以使用并发量为1,解决这个问题;
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
// 定义一个并发量为1 的队列, 用来保证响应数据的回调是串行的,但是数据解析还是并发执行的
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
虽然请求的回调是串行回调,但是请求完成后的数据解析是并发解析的,后续会分析...
- 进入AFHTTPSessionManager的GET 或 POST方法内部,可以看到内部是返回一个 NSURLSessionDataTask 对象,并且直接开始请求 resume ;
- (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;
}
- dataTaskWithHTTPMethod 方法首先会创建一个 NSMutableURLRequest 的对象, 并对传进来的参数进行合成,如get方法将参数放置于url,post将参数放置在请求体;其次会创建一个 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
{
// 1. 生成NSMutableURLRequest, 对参数进行合成
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;
}
// 2. 生成NSURLSessionDataTask任务对象, 并返回
__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;
}
- 进入 requestWithMethod 看内部如何实现,可以看出在该方法中创建了 NSMutableURLRequest 对象,然后遍历 mutableObservedChangedKeyPaths 集合,该集合是存放了外界自定义的一些属性,比如超时时间等,然后根据外界传输的请求数据格式,调用不同的代理方法,生成不一样的Request对象;
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
// 将用户自定义的属性放到mutableRequest,比如超时时间,是否允许蜂窝网络请求等
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
// 生成NSMutableURLRequest,下面这个方法是代理方法,每个请求的数据格式不一样,所以看子类的继承 Content-Type , NSDate 会不一样
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
- 介绍完如何NSMutableURLRequest的创建,来看看 NSURLSessionDataTask 的创建做了哪些事,进入dataTaskWithRequest方法内部;
- 可以看到首先创建了NSURLSessionDataTask对象,但是由于iOS8.0以下版本由于并发创建NSURLSessionDataTask会导致taskId不唯一,所以在iOS8.0以下,需要在 同步串行队列 中创建;
- 然后调用 addDelegateForDataTask 创建代理对象;
- 该代理对象主要作用是用来 解偶 AFURLSessionManager对象的,将回调,数据解析等都放置到代理对象中;
- 可以看到manage = self ,是对应AFURLSessionManager对象的,然后将代理对象存放着在 mutableTaskDelegatesKeyedByTaskIdentifier 字典中,self.mutableTaskDelegatesKeyedByTaskIdentifier[@(taskIdentifier)] = delegate;
- (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 {
// 1. 安全创建NSURLSessionDataTask对象
// 1.1 因为iOS8.0之前的系统,不能保证在并发线程中taskId唯一,所以用同步、串行队列进行创建
__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
// 2. 创建代理对象,用来处理请求完成回调
[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] initWithTask:dataTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- 然后介绍请求回调,可以看到AFURLSessionManager中的请求回调,都是将数据转发给 AFURLSessionManagerTaskDelegate 代理,然后让这个代理进行回调给外界;
- (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);
}
}
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
// 1. 请求完成后,回调到AFURLSessionManagerTaskDelegate中,进行数据处理后,将数据回调到最初的get回调(用户)
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
// 1.1 请求完成后,需要移除delegate
[self removeDelegateForTask:task];
}
// 2. 用户自定义的回调
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
- 转到 AFURLSessionManagerTaskDelegate 代理方法中,可以看到初始化了一个字典,存放解析的数据,回调有 block 和 通知 两种;响应数据的解析放在 异步并发队列 中执行,然后以block和通知方式回调给外界使用,整个请求过程结束,然后移除delegate对象;
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
// 1. 合成userInfo 的通知信息
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];
//We no longer need the reference, so nil it out to gain back some memory.
self.mutableData = nil;
}
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, error);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
} else {
// 2. 并发解析数据
dispatch_async(url_session_manager_processing_queue(), ^{
// 3. 使用代理方法, 解析响应的数据
NSError *serializationError = nil;
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
if (self.downloadFileURL) {
responseObject = self.downloadFileURL;
}
if (responseObject) {
userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
}
if (serializationError) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
}
// 4. 回调给用户解析后的数据, 整个请求结束
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];
});
});
});
}
}
上述只是通信模块的分析,其余模块后续补上。。。。。