AFNetworking 3.0 源码阅读笔记(三)

前言

AFURLSessionManager 绝对可以称得上是 AFNetworking 的核心,所以本文篇幅会相对长一点,但我保证绝对是满满的干货~


AFURLSessionManager

首先,在 AFURLSessionManager.h 中关于 AFURLSessionManager 的概述:

AFURLSessionManager creates and manages an NSURLSession object based on a specified NSURLSessionConfiguration object, which conforms to <NSURLSessionTaskDelegate>, <NSURLSessionDataDelegate>, <NSURLSessionDownloadDelegate>, and <NSURLSessionDelegate>.

最终可以归结为以下几点:

  1. 负责创建和管理 NSURLSession
  2. 管理 NSURLSessionTask
  3. 实现 NSURLSessionDelegate 等协议中的代理方法
  4. 使用 AFURLSessionManagerTaskDelegate 管理进度
  5. 使用 _AFURLSessionTaskSwizzling 调剂方法
  6. 引入 AFSecurityPolicy 保证请求的安全
  7. 引入 AFNetworkReachabilityManager 监控网络状态

创建和管理 NSURLSession

按惯例,我们由 AFURLSessionManager 的初始化方法:- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER; 进行展开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
- (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;
}

该方法主要完成如下工作:

  1. 初始化会话配置(NSURLSessionConfiguration),默认为 defaultSessionConfiguration
  2. 设置相应的 OperationQueue,决定请求过程中的一系列事件在哪个 OperationQueue 回调,这里是设置了最大并发量为 1 的队列,也就相当于串行队列了。(AFNetworing 2.0 版本是设置了一条常驻线程来响应所有网络请求的 delegate 事件)
  3. 初始化会话(session),并设置会话的代理及代理队列,delegate 用来处理请求中的各种事件,可以设置为 nil 使用系统提供的 delegate,但是要想支持后台传输数据必须提供自定义实现的 delegate;另外,NSURLSession 对象是强引用了 delegate,如果程序最终没有调用 invalidateAndCancel 方法来 invalidate 该 session 的话,则会造成内存泄漏
  4. 初始化管理响应序列化(AFJSONResponseSerializer),安全认证(AFSecurityPolicy)以及监控网络状态(AFNetworkReachabilityManager)的实例
  5. 初始化保存 data task 的字典(mutableTaskDelegatesKeyedByTaskIdentifier)

管理 NSURLSessionTask

接下来,在获得了 AFURLSessionManager 的实例之后,我们可以通过以下方法创建 NSURLSessionDataTask 的实例:

1
2
3
4
5
6
7
8
9
10
11
12
/**
Creates an `NSURLSessionDataTask` with the specified request.

@param request The HTTP request for the request.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/

- (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;

...

这里省略了一些返回 NSURLSessionTask 的方法,因为这些接口的形式都是差不多的。

扩展Difference between nullable, __nullable and _Nullable in Objective-C

下面,我们将以 - [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] 方法的实现为例,分析它是如何实例化并返回一个 NSURLSessionTask 的实例的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (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;
}

该方法主要完成如下工作:

  1. 调用 - [NSURLSession dataTaskWithRequest:] 方法传入 NSURLRequest
  2. 调用 - [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:] 方法返回一个 AFURLSessionManagerTaskDelegate 对象
  3. completionHandler uploadProgressBlockdownloadProgressBlock 传入该对象并在相应事件发生时进行回调

url_session_manager_create_task_safely 的调用是因为苹果框架中的一个 bug #2093,如果有兴趣可以看一下,在这里就不具体说明了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (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:] 来设置代理:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{

#1: 检查参数, 略

[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 等协议中的代理方法

首先,NSURLSession 的代理对象结构如下:

接下来,我们来看下具体的代理方法:

  • NSURLSessionDelegate
  • NSURLSessionTaskDelegate,遵守 NSURLSessionDelegate 协议
  • NSURLSessionDataDelegate,遵守 NSURLSessionTaskDelegate 协议,是网络请求通常遵循的协议,常用的方法:

    • 接受到服务响应时调用的方法

      1
      2
      3
      4
      5
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
      /**
      * 必须在该方法中对服务器的响应进行授权,才能继续接收服务器返回的数据,调用如下函数
      * completionHandler(NSURLSessionResponseAllow)
      */

    • 接收到服务器返回的数据时调用的方法

      1
      2
      3
      4
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
      /**
      * data:服务返回的数据,通常为 JSON 格式数据
      */

    • 请求完成时调用的方法(成功或失败)

      1
      2
      3
      4
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
      /**
      * 若出现错误,error 中存放错误信息
      */

  • NSURLSessionDownloadDelegate(通常用于下载大量数据),遵守 NSURLSessionTaskDelegate 协议,常用的方法:

    • 写入数据到临时文件时调用的方法(服务器返回一点就写入一点)

      1
      2
      3
      4
      5
      6
      - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:	(int64_t)totalBytesExpectedToWrite
      /**
      * totalBytesWritten,已写入数据的总长度
      * totalBytesExpectedToWrite:总共要写入数据的总长度
      * 可以在该方法中计算下载进度
      */

    • 遇到错误的时候调用

      1
      2
      3
      4
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
      /**
      *error:若遇到错误,则保存错误信息
      */

    • 用于断点下载的方法

      1
      2
      3
      4
      5
      - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
      /**
      * fileOffset:继续下载时,文件的开始位置
      * expectedTotalBytes:剩余的数据总数
      */

    • 下载完成时调用的方法

      1
      2
      3
      4
      5
      - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
      /**
      * location:下载的文件保存的临时位置
      * 需要将下载的文件保存在可以长期保存的位置
      */


使用 AFURLSessionManagerTaskDelegate 管理进度

在上面我们提到过 AFURLSessionManagerTaskDelegate 类,它主要为 task 提供进度管理功能,并在 task 结束时回调, 也就是调用在 - [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] 等方法中传入的 completionHandler

我们首先分析一下 AFURLSessionManagerTaskDelegate 是如何对进度进行跟踪的:

1
2
3
4
5
6
7
- (void)setupProgressForTask:(NSURLSessionTask *)task {

#1:设置在上传进度或者下载进度状态改变时的回调
true
#2:KVO

}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__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 属性进行键值观测:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (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. 调用传入的 completionHander block
  2. 发出 AFNetworkingTaskDidCompleteNotification 通知
1
2
3
4
5
6
7
8
9
10
11
12
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#1:获取数据, 存储 `responseSerializer` 和 `downloadFileURL`

if (error) {
#2:在存在错误时调用 `completionHandler`
} else {
truetrue#3:调用 `completionHandler`
}
}

这是整个代理方法的骨架,先看一下最简单的第一部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

// 具体可以查看 #issue 2672。这里主要是针对大文件的时候,性能提升会很明显
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];
// 此处不再需要 mutableData 了
self.mutableData = nil;
}

if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}

再来看第二部分:这部分代码从 mutableData 中取出了数据,设置了 userInfo

1
2
3
4
5
6
7
8
9
10
11
12
13
// 如果 task 出错了,处理 error 信息
// 所以对应的观察者在处理 error 的时候,比如可以先判断 userInfo[AFNetworkingTaskDidCompleteErrorKey] 是否有值,有值的话,就说明是要处理 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];
});
});

如果当前 manager 持有 completionGroup 或者 completionQueue 就使用它们。否则会创建一个 dispatch_group_t 并在主线程中调用 completionHandler 并发送通知(在主线程中)。

最后一部分:如果在执行当前 task 时没有遇到错误,那么先对数据进行序列化,然后同样调用 block 并发送通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
// 根据对应的 task 和 data 将 response data 解析成可用的数据格式,比如 JSON serializer 就将 data 解析成 JSON 格式
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
// 注意如果有 downloadFileURL,意味着 data 存放在了磁盘上了,所以此处 responseObject 保存的是 data 存放位置,供后面 completionHandler 处理。没有 downloadFileURL,就直接使用内存中的解析后的 data 数据
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 追加数据和处理下载的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (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 方法,使用下面的方法替换原有的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (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 方法只会在整个文件被引入时调用一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
+ (void)load {
if (NSClassFromString(@"NSURLSessionTask")) {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
// 首先构建一个 NSURLSession 对象 session,再通过 session 构建出一个 _NSCFLocalDataTask 变量
NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
#pragma clang diagnostic pop
// 获取到 af_resume 实现的指针
IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
Class currentClass = [localDataTask class];
// 检查当前 class 是否实现了 resume。如果实现了,继续第 4 步
while (class_getInstanceMethod(currentClass, @selector(resume))) {
// 获取到当前 class 的父类(superClass)
Class superClass = [currentClass superclass];
// 获取到当前 class 对于 resume 实现的指针
IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
// 获取到父类对于 resume 实现的指针
IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
// 如果当前 class 对于 resume 的实现和父类不一样(类似 iOS 7 上的情况),并且当前 class 的 resume 实现和 af_resume 不一样,才进行 method swizzling
if (classResumeIMP != superclassResumeIMP &&
originalAFResumeIMP != classResumeIMP) {
[self swizzleResumeAndSuspendMethodForClass:currentClass];
}
// 设置当前操作的 class 为其父类 class,重复步骤 3~8
currentClass = [currentClass superclass];
}

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

这里复杂的实现是为了解决 bug #2702


引入 AFSecurityPolicy 保证请求的安全

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

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

在 API 调用上,后两者都调用了 - [AFSecurityPolicy evaluateServerTrust:forDomain:] 方法来判断当前服务器是否被信任,我们会在接下来的文章中具体介绍这个方法的实现的作用。


引入 AFNetworkReachabilityManager 监控网络状态

AFSecurityPolicy 相同,AFURLSessionManager 对网络状态的监控是由 AFNetworkReachabilityManager 来负责的,它仅仅是持有一个 AFNetworkReachabilityManager 的对象。

真正需要判断网络状态时,仍然需要开发者调用对应的 API 获取网络状态


小结

  • AFURLSessionManager 是对 NSURLSession 的封装
  • 它通过 - [AFURLSessionManager dataTaskWithRequest:completionHandler:] 等接口创建 NSURLSessionDataTask 的实例
  • 持有一个字典 mutableTaskDelegatesKeyedByTaskIdentifier 管理这些 data task 实例
  • 引入 AFURLSessionManagerTaskDelegate 来对传入的 uploadProgressBlock downloadProgressBlock completionHandler 在合适的时间进行调用
  • 实现了全部的代理方法来提供 block 接口
  • 通过方法调剂在 data task 状态改变时,发出通知

参考