您的位置:首页 > 其它

AFNetworking 3.0 源码阅读笔记(三)

2016-11-14 17:28 549 查看

原文链接:http://itangqi.me/2016/05/09/the-notes-of-learning-afnetworking-three/

前言

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>
.

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

负责创建和管理
NSURLSession

管理
NSURLSessionTask

实现
NSURLSessionDelegate
等协议中的代理方法
使用
AFURLSessionManagerTaskDelegate
管理进度
使用
_AFURLSessionTaskSwizzling
调剂方法
引入
AFSecurityPolicy
保证请求的安全
引入
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;
}

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

初始化会话配置(NSURLSessionConfiguration),默认为
defaultSessionConfiguration

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

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

调用
- [NSURLSession dataTaskWithRequest:]
方法传入
NSURLRequest

调用
- [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:]
方法返回一个
AFURLSessionManagerTaskDelegate
对象
completionHandler
uploadProgressBlock
downloadProgressBlock
传入该对象并在相应事件发生时进行回调

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

1
2
3
4
5
6
7
8
9
10
11
1213
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
56

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

- (void)setupProgressForTask:(NSURLSessionTask *)task {

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

}

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

1
2
3
4
5
6
7
8
9
10
11
1213
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
1213
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
1213
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:
中:

调用传入的
completionHander
block
发出
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
1213
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
1213

// 如果 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
1213
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
1213
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
的唯一功能就是修改
NSURLSessionTask

resume
suspend
方法,使用下面的方法替换原有的实现:

1
2
3
4
5
6
7
8
9
10
11
1213
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
1213
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];
}
}

首先用
NSClassFromString(@"NSURLSessionTask")
判断当前部署的 iOS 版本是否含有类
NSURLSessionTask

因为 iOS 7 和 iOS 8 上对于
NSURLSessionTask
的实现不同,所以会通过
- [NSURLSession dataTaskWithURL:]
方法返回一个
NSURLSessionTask
实例
取得当前类
_AFURLSessionTaskSwizzling
中的实现
af_resume

如果当前类
currentClass
resume
方法
真:5
假:6

使用
swizzleResumeAndSuspendMethodForClass:
调剂该类的
resume

suspend
方法
currentClass = [currentClass superclass]


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

引入
AFSecurityPolicy
保证请求的安全

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

初始化
self.securityPolicy = [AFSecurityPolicy defaultPolicy]

收到连接层的验证请求时
任务接收到验证请求时
在 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 状态改变时,发出通知

参考

AFNetworking
的核心 AFURLSessionManager(二)
【原】AFNetworking源码阅读(四)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  对象