网络是APP开发中非常重要的一部分,除非这个APP是本地自玩,否则就离不开网络。在iOS开发中,我们一般都会去使用别人造好的轮子,其中最有名也最常用的非AFNetworking莫属。这篇文章就深入探讨一下AFNetworking是如何工作的。

概述


我们先来看看AFNetworking整个架构体系:



首先,我们有两个问题需要了解:

  • 如何使用NSURLSession发出HTTP请求
  • 如何使用AFNetworking发出HTTP请求

NSURLSession


NSURLSession以及与它相关的类为我们提供了下载内容的API,这个API提供了一系列的代理方法来支持身份认证,并且支持后台下载。

使用NSURLSession来运行HTTP请求并且获得数据总共有五个步骤:

  1. 实例化一个NSURLRequest/NSMutableURLRequest,设置URL
  2. 通过- shareSession方法获取NSURLSession
  3. 在session上调用- dataTaskWithRequest:completionHandler:方法返回一个NSURLSessionDataTask
  4. 调用dataTask的- resume,开始执行任务
  5. 在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请求有两个步骤

  1. 以服务器的主机地址或者域名生成一个AFHTTPSessionManager的实例
  2. 调用- 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] // 负责序列化响应

从这个初始化方法的调用栈,我们可以非常清晰地了解这个架构的结构:

  • 其中AFURLSessionManagerAFHTTPSessionManager的父类
  • AFURLSessionManager负责生成NSURLSession的实例,管理AFSecurityPolicyAFNetworkReachabilityManager,来保证请求的安全和查看网络连接情况,它有一个AFJSONResponseSerializer的实例来序列化HTTP响应
  • AFHTTPSessionManager有着自己的AFHTTPRequestSerialierAFJSONResponseSerializer来管理请求和响应的序列化,同时依赖父类提供的接口保证安全、监控网络状态,实现发出HTTP请求这一核心功能

初始化方法很好地揭示了AFNetworking整个框架的架构,接下来我们要通过分析另一个方法- GET:parameters:process:success:failure:的调用栈,看一下HTTP请求是如何发出的:

- [AFHTTPSessionManager GET:parameters:process:success:failure:]
- [AFHTTPSessionManager dataTaskWithHTTPMethod:parameters:uploadProgress:downloadProgress:success:failure:] // 返回 NSURLSessionDataTask #1
- [AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:] // 返回 NSMutableURLRequest
- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] // 返回 NSURLSessionDataTask #2
- [NSURLSession dataTaskWithRequest:] // 返回 NSURLSessionDataTask #3
- [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;
//为已有的task设置代理
[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. 初始化 会话配置 (NSURLSessionConfiguration),默认为defaultSessionConfiguration
  2. 初始化 会话 (session),并设置会话的代理以及代理列队
  3. 初始化管理 响应序列化 (AFJSONResponseSerializer),安全认证 (AFSecurityPolicy) 以及 监控网络状态 (AFNetworkReachabilityManager) 的实例
  4. 初始化保存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 uploadProgressBlockdownloadProgressBlock传入该对象并在相应事件发生时进行回调
- (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
}

该方法的实现有两个部分,一部分是对代理持有的两个属性uploadProgressdownloadProgress设置回调

__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:中:

  1. 调用传入的completionHanderblock
  2. 发出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;
//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;
}

这部分代码从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的唯一功能就是修改NSURLSessionTaskresumesuspend方法,使用下面的方法替换原有的实现

- (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];
}
}
  1. 首先用NSClassFromString(@"NSURLSessionTask")判断当前部署的iOS版本是否含有类NSURLSessionTask
  2. 因为iOS7和iOS8上对于NSURLSesionTask的实现不同,所以会通过- [NSURLSession dataTaskWithURL:]方法返回一个NSURLSessionTask实例
  3. 取得当前类_AFURLSessionTaskSwizzling中的实现af_resume
  4. 判断当前类currentClassresume方法
  5. 使用swizzleResumeAndSuspendMethodForClass:调剂该类的resumesuspend方法
  6. currentClass = [currentClass superclass]

引入AFSecurityPolicy保证请求的安全


AFSecurityPolicyAFNetworking用来保证HTTP请求安全的类,它被AFURLSessionManager持有,如果你在AFURLSessionManager的实现文件中搜索self.securityPolicy,你只会得到三条结果:

  1. 初始化self.securityPolicy = [AFSecurityPolicy defaultPolicy]
  2. 收到连接层的验证请求时
  3. 任务接收到验证请求时

在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 状态改变时,发出通知