AFN2.0 和3.0的区别和改动
AFN2.0:
1.对NSURLSession的封装
2.对AFURLConnection的封装
3.对HTTPS网络安全请求做了一个包装
4.做了一个网络连接管理的一个包装,
AFN3.0:
1>添加进度回调
2> 去掉所有AFURLConnection
AF的5个功能模块:
- 网络通信模块(AFURLSessionManager、AFHTTPSessionManger)
- 网络状态监听模块(Reachability)
- 网络通信安全策略模块(Security)
- 网络通信信息序列化/反序列化模块(Serialization)
- 对于iOS UIKit库的扩展(UIKit)
核心模块:网络通信模块AFURLSessionManager
AF3.x是基于NSURLSession来封装的。所以这个类围绕着NSURLSession做了一系列的上层封装。而其余的四个模块,均是为了配合AFURLSessionManager类的网络通信做一些必要的处理工作。结构关系如下:
其中AFHTTPSessionManager是继承于AFURLSessionManager的
我们一般做网络请求都是用这个类,但是它本身是没有做实事的,只是做了一些简单的封装,把请求逻辑分发给父类AFURLSessionManager去做。
一.其中AFHTTPSessionManager做的事情是:
1.创建管理对象,封装对外接口
2.在GET和POST方法中,调用父类方法把从父类获取到的task ,resume
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);
}
}
}];
3.把传过来的参数,编码成我们请求时需要的request,并且传给父类去做网络请求
做这个事情的代码如下:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
//断言,debug模式下,如果缺少改参数,crash
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
//将request的各种属性循环遍历
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
//如果自己观察到的发生变化的属性,在这些方法里
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
//把给自己设置的属性给request设置
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
//将传入的parameters进行编码,并添加到request中
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
在AFN中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理
二.AFURLSessionManager的初始化方法
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
self.operationQueue = [[NSOperationQueue alloc] init];
//queue并发线程数为1,这个是代理回调的queue
self.operationQueue.maxConcurrentOperationCount = 1;
//注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
//各种响应转码
self.responseSerializer = [AFJSONResponseSerializer serializer];
//ssl证书,是验证证书,还是公钥,还是不用
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
// 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典(重点,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理) ===============
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// =============== 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全===============
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
// =============== 为所管理的session的所有task设置完成块,此方法为生成session之后就调用
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
//开始的时候应该什么都没有
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}
其中两个方法比较重要:
1. self.operationQueue.maxConcurrentOperationCount = 1;
2. [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
//置空处理
}];
其作用为:
- 第一是让回调的代理queue是串行的,即请求完成的task只能一个个被回调。
- 第二是清空了session中所有task。
其目的:
第一个:
第二个:我们知道这里是初始化方法,按理说session中不会有任何task。但是我们有一种后台session,当从后台回来的时候,根据一个ID,就可以重新恢复这个session,这时候其中就会有之前未完成的task了。
所以:
而这里这么做的目的就是防止一些之前的后台请求任务,导致程序的crash
接着是dataTaskWithRequest方法:
- (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;
//第一件事,创建NSURLSessionDataTask,里面适配了Ios8以下taskIdentifiers,函数创建task对象。
//其实现应该是因为iOS 8.0以下版本中会并发地创建多个task对象,而同步有没有做好,导致taskIdentifiers 不唯一…这边做了一个串行处理
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
这里所做的有两件事:
1.调用session的方法,传request过去去生成task。
- 给每个task创建并对应一个AF的代理对象,这基本上是这个类的核心所在了,这个代理对象为其对应的task做数据拼接及成功回调。
正如上面所说,AFN中每一个task都会被对应生成一个delegate并与之匹配,其所有核心方法都为代理调用
- (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];
// AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系
delegate.manager = self;
delegate.completionHandler = completionHandler;
//这个taskDescriptionForSessionTasks用来发送开始和挂起通知的时候会用到,就是用这个值来Post通知,来两者对应
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
// ***** 将AF delegate对象与 dataTask建立关系
[self setDelegate:delegate forTask:dataTask];
// 设置AF delegate的上传进度,下载进度块。
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
//断言,如果没有这个参数,debug下crash在这
NSParameterAssert(task);
NSParameterAssert(delegate);
//加锁保证字典线程安全
[self.lock lock];
// 将AF delegate放入以taskIdentifier标记的词典中(同一个NSURLSession中的taskIdentifier是唯一的)
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 为AF delegate 设置task 的progress监听
[delegate setupProgressForTask:task];
//添加task开始和暂停的通知
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
就这么两个方法创建了一个AFURLSessionManagerTaskDelegate的代理,把这个代理和task的taskIdentifier一一对应,放在我们最早初始化(initWithSessionConfiguration方法中创建的mutableTaskDelegatesKeyedByTaskIdentifier)的字典里,建立起映射。
这里所做的还包括对task进度的监听和挂起与重新开始的通知。
做完以上操作后,在AFHTTPSessionManager中调用resume方法
[dataTask resume];
其中主要的三个代理有:
1.完成的代理
2.收到数据的代理
3.以及下载完成的代理
AFN中还为每个代理方法,声明了对应的属性Block,我们可以利用这些Block,做一些自定义的处理,Block会随着代理调用而被调用,这些代理帮我们做了一些类似数据分片、断电续传、https认证等工作
以其中一个为例:
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
//根据task去取我们一开始创建绑定的delegate
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
//把代理转发给我们绑定的delegate
[delegate URLSession:session task:task didCompleteWithError:error];
//转发完移除delegate
[self removeDelegateForTask:task];
}
//公用Block回调
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
其中的代理调用的方法实现如下:
//AF实现的代理!被从urlsession那转发到这
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//1)强引用self.manager,防止被提前释放;因为self.manager声明为weak,类似Block
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
//用来存储一些相关信息,来发送通知用的
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
//存储responseSerializer响应解析对象
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
//注意这行代码的用法,感觉写的很Nice...把请求到的数据data传出去,然后就不要这个值了释放内存
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;
}
//继续给userinfo填数据
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
//错误处理
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
//可以自己自定义完成组 和自定义完成queue,完成回调
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 {
//url_session_manager_processing_queue AF的并行队列
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
//解析数据
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
//如果是下载文件,那么responseObject为下载的路径
if (self.downloadFileURL) {
responseObject = self.downloadFileURL;
}
//写入userInfo
if (responseObject) {
userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
}
//如果解析错误
if (serializationError) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
}
//回调结果
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];
});
});
});
}
#pragma clang diagnostic pop
}