网络是APP开发中非常重要的一部分,除非这个APP是本地自玩,否则就离不开网络。在iOS开发中,我们一般都会去使用别人造好的轮子,其中最有名也最常用的非AFNetworking
莫属。这篇文章就深入探讨一下AFNetworking
是如何工作的。
概述
我们先来看看AFNetworking
整个架构体系:
首先,我们有两个问题需要了解:
如何使用NSURLSession发出HTTP请求
如何使用AFNetworking发出HTTP请求
NSURLSession
NSURLSession
以及与它相关的类为我们提供了下载内容的API,这个API提供了一系列的代理方法来支持身份认证,并且支持后台下载。
使用NSURLSession
来运行HTTP请求并且获得数据总共有五个步骤:
实例化一个NSURLRequest/NSMutableURLRequest
,设置URL
通过- shareSession
方法获取NSURLSession
在session上调用- dataTaskWithRequest:completionHandler:
方法返回一个NSURLSessionDataTask
调用dataTask的- resume
,开始执行任务
在completionHandler中将数据编码,返回字符串
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"https://github.com" ]];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding ];
NSLog (@"%@" , dataStr);
}];
[task resume];
这一段代码可以说是使用NSURLSession
发送请求最简单的一段代码了,当你运行这段代码会在控制台看到github首页的html
<!DOCTYPE html>
<html lang="en" class="">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
<meta charset='utf-8'>
...
</head>
...
</html>
想对NSURLSession
有更深的了解,请点这里
AFNetworking
AFNetworking的使用也比较简单的,使用它来发送HTTP请求有两个步骤
以服务器的主机地址或者域名生成一个AFHTTPSessionManager
的实例
调用- GET:parameters:progress:success:failure:
方法
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[[NSURL alloc] initWithString:@"hostname" ]];
[manager GET:@"relative_url" parameters:nil progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog (@"%@" ,responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog (@"%@" , error);
}];
注意:在iOS9中,苹果默认全局HTTPS,如果你要发送不安全的HTTP请求,需要在info.plist中加入如下键值对才能发出不安全的HTTP请求 还有一件事情是要注意的是,AFNetworking默认接收json格式的响应(因为这是在iOS平台上的框架,一般不需要text/html),如果想要返回html,需要设置acceptableContentTypes
。
AFNetworking的调用栈
刚才我们写了一个简单的网络请求,接下来,我们来看看AFHTTPSessionManager
的初始化方法- initWithBaseURL:
的调用栈:
- [AFHTTPSessionManager initWithBaseURL:]
- [AFHTTPSessionManager initWithBaseURL:sessionConfiguration:]
- [AFURLSessionManager initWithSessionConfiguration:]
- [NSURLSession sessionWithConfiguration:delegate:delegateQueue:]
- [AFJSONResponseSerializer serializer]
- [AFSecurityPolicy defaultPolicy]
- [AFNetworkReachabilityManager sharedManager]
- [AFHTTPRequestSerializer serializer]
- [AFJSONResponseSerializer serializer]
从这个初始化方法的调用栈,我们可以非常清晰地了解这个架构的结构:
其中AFURLSessionManager
是AFHTTPSessionManager
的父类
AFURLSessionManager
负责生成NSURLSession
的实例,管理AFSecurityPolicy
和AFNetworkReachabilityManager
,来保证请求的安全和查看网络连接情况,它有一个AFJSONResponseSerializer
的实例来序列化HTTP响应
AFHTTPSessionManager
有着自己的AFHTTPRequestSerialier
和AFJSONResponseSerializer
来管理请求和响应的序列化,同时依赖父类提供的接口保证安全、监控网络状态,实现发出HTTP请求这一核心功能
初始化方法很好地揭示了AFNetworking整个框架的架构,接下来我们要通过分析另一个方法- GET:parameters:process:success:failure:
的调用栈,看一下HTTP请求是如何发出的:
- [AFHTTPSessionManager GET:parameters:process:success:failure:]
- [AFHTTPSessionManager dataTaskWithHTTPMethod:parameters:uploadProgress:downloadProgress:success:failure:]
- [AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:]
- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:]
- [NSURLSession dataTaskWithRequest:]
- [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:]
- [AFURLSessionManagerTaskDelegate init]
- [AFURLSessionManager setDelegate:forTask:]
- [NSURLSessionDataTask resume]
在这里 #1
#2
#3
处返回的是同一个dataTask,我们可以看到,在#3
出调用的方法- [NSURLSession dataTaskWithRequest:]
和只使用NSURLSession
发出HTTP请求时调用的方法- [NSURLSession dataTaskWithRequest:completionHandler:]
差不多。在这个地方返回dataTask之后,我们再调用- resume
方法执行请求,并在某些事件执行时通知代理AFURLSessionManagerTaskDelegate
AFNetworking的核心AFURLSessionManager
AFURLSessionManager
绝对可以称得上是AFNetworking的核心
负责创建和管理NSURLSession
管理NSURLSessionTask
实现NSURLSessionDelegate等协议中的代理方法
使用_AFURLSessionTaskSwizzling调剂方法
引入AFSecurityPolicy保证请求的安全
引入AFNetworkingReachabilityManager监控网络状态
这一节将会着重介绍上面七个功能中的前五个,分析它是如何包装NSURLSession
以及众多代理方法的。
创建和管理NSURLSession
使用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];
self .operationQueue.maxConcurrentOperationCount = 1 ;
self .session = [NSURLSession sessionWithConfiguration:self .sessionConfiguration delegate:self delegateQueue:self .operationQueue];
self .responseSerializer = [AFJSONResponseSerializer serializer];
self .securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self .reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
self .mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
self .lock = [[NSLock alloc] init];
self .lock.name = AFURLSessionManagerLockName;
[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 ;
}
在初始化方法中,需要完成初始化一些自己持有的特例:
初始化 会话配置 (NSURLSessionConfiguration),默认为defaultSessionConfiguration
初始化 会话 (session),并设置会话的代理以及代理列队
初始化管理 响应序列化 (AFJSONResponseSerializer),安全认证 (AFSecurityPolicy) 以及 监控网络状态 (AFNetworkReachabilityManager) 的实例
初始化保存data task的字典(mutableTaskDelegatesKeysByTaskIdentifier)
管理NSURLSessionTask
接下来,在获得了AFURLSessionManager
的实例之后,我们可以通过以下方法创建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;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
fromFile:(NSURL *)fileURL
progress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
...
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
...
这里省略了一些返回NSURLSessionTask的方法,因为这些接口的形式都是差不多的。
我们将以 [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:]
方法的实现为例,分析它是如何实例化并返回一个NSURLSessionTask
的实例的:
- (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 ;
url_session_manager_create_task_safely(^{
dataTask = [self .session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
调用- [NSURLSession dataTaskWithRequest:]
方法传入NSURLRequest
调用- [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:]
方法返回一个AFURLSessionManagerTaskDelegate
对象
将completionHandler
uploadProgressBlock
和downloadProgressBlock
传入该对象并在相应事件发生时进行回调
- (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];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
在这个方法中同时调用了另一个方法- [AFURLSessionManager setDelegate:forTask:]
来设置代理:
- (void )setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert (task);
NSParameterAssert (delegate);
[self .lock lock];
self .mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
[self .lock unlock];
}
正如上面所提到的,AFURLSessionManager
就是通过字典mutableTaskDelegatesKeyedByTaskIdentifier
来存储并管理每一个NSURLSessionTask
,它以taskIdentifier
为键存储task。
该方法使用NSLock
来保证不同线程使用mutableTaskDelegatesKeyedByTaskIdentifier
时,不会出现线程竞争的问题。
同时调用-setupProgressForTask
,我们会在下面具体介绍这个方法。
实现NSURLSessionDelegate等协议中的代理方法
在AFURLSessionManager
的头文件中可以看到,它遵循了多个协议,其中包括:
NSURLSessionDelegate
NSURLSessionTaskDelegate
NSURLSessionDataDelegate
NSURLSessionDownloadDelegate
它的初始化方法- [AFURLSessionManager initWithSessionConfiguration:]
将NSURLSession
的代理指向self,然后实现这些方法,提供更简洁的block的接口:
- (void )setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;
- (void )setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
...
它为所有的代理协议都提供了对应的block接口,方法实现的思路都是相似的,我们以- [AFNRLSessionManager setSessionDidBecomeInvalidBlock:]
为例。
首先调用setter方法,将block存入sessionDidBecomeInvalid
属性中:
- (void )setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
self .sessionDidBecomeInvalid = block;
}
当代理方法调用时,如果存在对应的block,会执行对应的block:
- (void )URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error
{
if (self .sessionDidBecomeInvalid) {
self .sessionDidBecomeInvalid(session, error);
}
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}
其他相似的接口实现也都差不多,这里直接跳过了。
使用AFURLSessionManagerTaskDelegate管理进度
在上面我们提到过AFURLSessionManagerTaskDelegate
类,它主要为task提供进度管理功能,并在task结束时回调,也就是调用在- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:]
等方法中传入的completionHandler
。
我们首先分析一下AFURLSessionManagerTaskDelegate
是如何对进度进行跟踪的:
- (void )setupProgressForTask:(NSURLSessionTask *)task {
#1:设置在上传进度或者下载进度状态改变时的回调
#2:KVO
}
该方法的实现有两个部分,一部分是对代理持有的两个属性uploadProgress
和downloadProgress
设置回调
__weak __typeof__(task) weakTask = task;
self .uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
[self .uploadProgress setCancellable:YES ];
[self .uploadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self .uploadProgress setPausable:YES ];
[self .uploadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self .uploadProgress respondsToSelector:@selector (setResumingHandler:)]) {
[self .uploadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
这里只有对uploadProgress
设置回调的代码,设置downloadProgress
与这里完全相同
主要目的是在对应NSProgress
的状态改变时,调用resume
suspend
等方法改变task的状态。
第二部分是对task和NSProgress
属性进行键值观测:
[task addObserver:self
forKeyPath:NSStringFromSelector (@selector (countOfBytesReceived))
options:NSKeyValueObservingOptionNew
context:NULL ];
[task addObserver:self
forKeyPath:NSStringFromSelector (@selector (countOfBytesExpectedToReceive))
options:NSKeyValueObservingOptionNew
context:NULL ];
[task addObserver:self
forKeyPath:NSStringFromSelector (@selector (countOfBytesSent))
options:NSKeyValueObservingOptionNew
context:NULL ];
[task addObserver:self
forKeyPath:NSStringFromSelector (@selector (countOfBytesExpectedToSend))
options:NSKeyValueObservingOptionNew
context:NULL ];
[self .downloadProgress addObserver:self
forKeyPath:NSStringFromSelector (@selector (fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL ];
[self .uploadProgress addObserver:self
forKeyPath:NSStringFromSelector (@selector (fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL ];
在observeValueForKeypath:ofObject:change:context:
方法中改变进度,并调用block
- (void )observeValueForKeyPath:(NSString *)keyPath ofObject:(id )object change:(NSDictionary <NSString *,id > *)change context:(void *)context {
if ([object isKindOfClass:[NSURLSessionTask class ]]) {
if ([keyPath isEqualToString:NSStringFromSelector (@selector (countOfBytesReceived))]) {
self .downloadProgress.completedUnitCount = [change[@"new" ] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector (@selector (countOfBytesExpectedToReceive))]) {
self .downloadProgress.totalUnitCount = [change[@"new" ] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector (@selector (countOfBytesSent))]) {
self .uploadProgress.completedUnitCount = [change[@"new" ] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector (@selector (countOfBytesExpectedToSend))]) {
self .uploadProgress.totalUnitCount = [change[@"new" ] longLongValue];
}
}
else if ([object isEqual:self .downloadProgress]) {
if (self .downloadProgressBlock) {
self .downloadProgressBlock(object);
}
}
else if ([object isEqual:self .uploadProgress]) {
if (self .uploadProgressBlock) {
self .uploadProgressBlock(object);
}
}
}
对象的某些属性改变时更新NSProgress
对象或使用block传递NSProgress
对象self.uploadProgressBlock(object)
。
代理方法 URLSession:task:didCompleteWithError:
在每一个NSURLSessionTask
结束时,都会在代理方法URLSession:task:didCompleteWithError:
中:
调用传入的completionHander
block
发出AFNetworkingTaskDidCompleteNotification
通知
- (void )URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#1:获取数据, 存储 `responseSerializer` 和 `downloadFileURL`
if (error) {
#2:在存在错误时调用 `completionHandler`
} else {
#3:调用 `completionHandler`
}
}
这是整个代理方法的骨架,先看一下最简单的第一部分代码:
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
NSData *data = nil ;
if (self .mutableData) {
data = [self .mutableData copy ];
self .mutableData = nil ;
}
if (self .downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self .downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
这部分代码从mutableData
中取出数据,设置了userInfo
。
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];
});
});
如果当前manager持有completionGroup
或者completionQueue
就是用它们。否则会创建一个dispatch_group_t
并在主线程中调用completionHandler
并发送通知(在主线程中)。
如果在执行当前task时没有遇到错误,那么先对数据进行序列化,然后同样调用block并发送通知。
dispatch_async (url_session_manager_processing_queue(), ^{
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;
}
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];
});
});
});
代理方法URLSession:dataTask:didReceiveData:和URLSession:downloadTask:didFinishDownloadingToURL: 这两个代理方法分别会在收到数据或者完成下载对应文件时调用,作用分别是为mutableData追加数据和处理下载的文件:
- (void )URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
[self .mutableData appendData:data];
}
- (void )URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSError *fileManagerError = nil ;
self .downloadFileURL = nil ;
if (self .downloadTaskDidFinishDownloading) {
self .downloadFileURL = self .downloadTaskDidFinishDownloading(session, downloadTask, location);
if (self .downloadFileURL) {
[[NSFileManager defaultManager] moveItemAtURL:location toURL:self .downloadFileURL error:&fileManagerError];
if (fileManagerError) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
}
}
}
}
使用 _AFURLSessionTaskSwizzling 调剂方法
_AFURLSessionTaskSwizzling
的唯一功能就是修改NSURLSessionTask
的resume
和suspend
方法,使用下面的方法替换原有的实现
- (void )af_resume {
NSAssert ([self respondsToSelector:@selector (state)], @"Does not respond to state" );
NSURLSessionTaskState state = [self state];
[self af_resume];
if (state != NSURLSessionTaskStateRunning ) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self ];
}
}
- (void )af_suspend {
NSAssert ([self respondsToSelector:@selector (state)], @"Does not respond to state" );
NSURLSessionTaskState state = [self state];
[self af_suspend];
if (state != NSURLSessionTaskStateSuspended ) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self ];
}
}
这样做的目的是为了在方法resume
或者suspend
被调用时发送通知。
具体方法调剂的过程是在+load
方法中进行的
load
方法只会在整个文件被引入时调用一次
+ (void )load {
if (NSClassFromString (@"NSURLSessionTask" )) {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil ];
#pragma clang diagnostic pop
IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class ], @selector (af_resume)));
Class currentClass = [localDataTask class ];
while (class_getInstanceMethod(currentClass, @selector (resume))) {
Class superClass = [currentClass superclass];
IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector (resume)));
IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector (resume)));
if (classResumeIMP != superclassResumeIMP &&
originalAFResumeIMP != classResumeIMP) {
[self swizzleResumeAndSuspendMethodForClass:currentClass];
}
currentClass = [currentClass superclass];
}
[localDataTask cancel];
[session finishTasksAndInvalidate];
}
}
首先用NSClassFromString(@"NSURLSessionTask")
判断当前部署的iOS版本是否含有类NSURLSessionTask
因为iOS7和iOS8上对于NSURLSesionTask
的实现不同,所以会通过- [NSURLSession dataTaskWithURL:]
方法返回一个NSURLSessionTask
实例
取得当前类_AFURLSessionTaskSwizzling
中的实现af_resume
判断当前类currentClass
有resume
方法
使用swizzleResumeAndSuspendMethodForClass:
调剂该类的resume
和suspend
方法
currentClass = [currentClass superclass]
引入AFSecurityPolicy保证请求的安全
AFSecurityPolicy
是AFNetworking
用来保证HTTP请求安全的类,它被AFURLSessionManager
持有,如果你在AFURLSessionManager
的实现文件中搜索self.securityPolicy,你只会得到三条结果:
初始化self.securityPolicy = [AFSecurityPolicy defaultPolicy]
收到连接层的验证请求时
任务接收到验证请求时
在API调用上,后两者都调用了- [AFSecurityPolicy evaluateServerTrust:forDomain:]
方法来判断当前服务器是否被信任,我们会在接下来的文章中具体介绍这个方法的实现的作用。
- (void )URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling ;
__block NSURLCredential *credential = nil ;
if (self .sessionDidReceiveAuthenticationChallenge) {
disposition = self .sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
} else {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust ]) {
if ([self .securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential ;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling ;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge ;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling ;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}
如果没有传入taskDidReceiveAuthenticationChallenge
block,只有在上述方法返回YES时,才会获得认证凭证credential
。
引入AFNetworkingReachabilityManager监控网络状态
与AFSecurityPolicy
相同,AFURLSessionManager
对网络状态的监控是由AFNetworkReachabilityManager
来负责的,它仅仅是持有一个AFNetworkReachabilityManager
的对象。
小结
AFURLSessionManager
是对NSURLSession
的封装
它通过- [AFURLSessionManager dataTaskWithRequest:completionHandler:]
等接口创建NSURLSessionDataTask
的实例
持有一个字典mutableTaskDelegatesKeyedByTaskIdentifier
管理这些data task 实例
引入AFURLSessionManagerTaskDelegate
来对传入的uploadProgressBlock
downloadProgressBlock
completionHandler
在合适的时间进行调用
实现了全部的代理方法来提供block接口
通过方法调剂在data task 状态改变时,发出通知