介绍:
AFNetworking是适用于iOS,macOS,watchOS
和tvOS
的的网络库。它构建于Foundation URL
系统之上,扩展了Cocoa内置的强大的高级网络抽象。它采用模块化架构,设计精良,功能丰富的API,使用起来非常简单。
GitHub地址:https://github.com/AFNetworking/AFNetworking
安装:
使用CocoaPods安装
pod 'AFNetworking'
版本要求:
使用:
示例:
[[AFHTTPSessionManager manager] GET: `url地址...` parameters: `请求参数...` progress:^(NSProgress * _Nonnull downloadProgress) {
// 请求进度...
}success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// 成功回调...
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 失败回调...
}];
这是一个很简单的GET
请求例子, 使用AFHTTPSessionManager
的实例对象直接调用封装好的Get方法
,传入请求Url
和 参数
,就可以获取到请求结果.是不是非常方便; 当然我们在实际开发中不会直接这么使用, 可能还需要做一些其他的设置操作等, 后面会介绍具体使用以及源码解析;
注意: 在 iOS9以后,苹果默认全局 HTTPS,如果你要发送不安全的 HTTP 请求,需要在 info.plist 中加入如下键值对才能发出不安全的 HTTP 请求:
或者使用代码添加
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
AFN结构:
AFNetworking
框架的文件目录,如下图所示:
框架类文件还是比较多, 可以根据目录结构大致的了解每个类的作用,如果根据功能模块
来划分,可以分为5种:
- NSURLSession - 负责网络通信工作(核心)
- Serialization - 负责数据的序列化工作
- Reachability - 负责网络状态监听工作
- Security - 负责安全认证工作
- UIKit - 对UIKit框架扩展
源码分析
1. NSURLSession文件
NSURLSession
文件夹里面有个2个类AFHTTPSessionManager
和AFURLSessionManager
,这个模块是AFN
框架中的核心部分
AFURLSessionManager
类用于管理NSURLSession
对象, 对NSURLSession
进行高度封装,如果对NSURLSession
不了解的请参考上一篇:NSURLSession介绍与使用;AFURLSessionManager
可以说是AFN
核心中的核心了;AFHTTPSessionManager
作为AFURLSessionManager
的子类, 对AFURLSessionManager
的接口又进行了上层封装, 提供更加简洁易用的接口给我们使用,同样AFN
也建议我们在扩展时可以继承AFHTTPSessionManager
进行使用;
2. AFHTTPSessionManager
AFHTTPSessionManager
提供了以下接口给我们使用,代码如下:
// baseUrl
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 请求序列化器
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 响应序列化器
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
// 安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
// 初始化
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// get
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// post
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// .....Head, Put, Patch, Delete等请求方法, 和上面类似
上述代码大家都非常熟悉, 平时我们在开发中基本都会用到以上接口, 通过简单的几句代码就可以进行各类网络通信, 接下来我们看下.m
文件都做了哪些事情:
.m
内部有一个baseURL
属性, 用于保存请求服务器地址信息
@property (readwrite, nonatomic, strong) NSURL *baseURL;
然后所有的get, post网络
请求都会调用以下方法:
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure{
NSError *serializationError = nil;
// 请求序列化
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
// 错误处理
if (serializationError) {
...略...
}
// 创建 task
__block NSURLSessionDataTask *dataTask = nil;
// 通过父类方法进行task 创建
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
...略...
}];
return dataTask;
}
在上述方法中会进行以下操作
- 对请求进行序列化操作
- 调用父类的
-dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler
方法, 在父类(AFURLSessionManager
)中完成NSURLSessionDataTask
创建,以及网络通信工作; - 在获取网络请求结果后,通过
completionHandler
进行回调
总结: AFHTTPSessionManager
实际上所做的工作并不多,他主要是对AFURLSessionManager
进行上层封装,提供简单易用的接口给我们使用, 真正的核心操作都是在AFURLSessionManager
内完成的,接下来就重点分析一下AFURLSessionManager
的源码
3. AFURLSessionManager
AFURLSessionManager
可以称得上是 AFNetworking 的核心。
初始化
我们看一下AFURLSessionManager
是如何初始化的:
// 通过 会话配置 进行初始化
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
// 判断有没有configuration
if (!configuration) {
// 外部没有指定则初始化默认会话配置
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
// 会话配置
self.sessionConfiguration = configuration;
// 创建会话队列
self.operationQueue = [[NSOperationQueue alloc] init];
// 最大并发操作数
self.operationQueue.maxConcurrentOperationCount = 1;
// 初始化 session 会话,并设置session代理
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
// 初始化JSON序列化器(`AFJSONResponseSerializer`是`AFHTTPResponseSerializer`的子类,用于验证和解码JSON响应。)
self.responseSerializer = [AFJSONResponseSerializer serializer];
// 初始化安全策略
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
// 初始化网络监听器
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
// 初始化 data task字典
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
..为已有的 task 设置代理, 略..
return self;
}
在上面的初始化方法中:
- 初始化会话配置(NSURLSessionConfiguration),默认为
defaultSessionConfiguration
- 初始化会话(session),并设置会话的代理以及代理队列
- 初始化管理响应序列化(AFJSONResponseSerializer),安全认证(AFSecurityPolicy)以及监控网络状态(AFNetworkReachabilityManager)的实例
- 初始化保存 data task 的字典(mutableTaskDelegatesKeyedByTaskIdentifier)
管理 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;
// ...略...接口和上面差不多
接下来以 - [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] 方法的实现为例,分析它是如何实例化并返回一个 NSURLSessionTask 的实例的:
// 创建 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 {
// task 实例
__block NSURLSessionDataTask *dataTask = nil;
// 解决苹果框架中的一个 bug
url_session_manager_create_task_safely(^{
// 创建task
dataTask = [self.session dataTaskWithRequest:request];
});
// 给 tase 添加代理
[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{
// 创建一个SessionManager代理实例
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
// 代理拥有 session 实例
delegate.manager = self;
// 代理拥有completionHandler
delegate.completionHandler = completionHandler;
// 为任务提供描述性标签。
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
// 为 task 添加代理
[self setDelegate:delegate forTask:dataTask];
// 代理永久uploadProgressBlock
delegate.uploadProgressBlock = uploadProgressBlock;
// 代理永久uploadProgressBlock
delegate.downloadProgressBlock = downloadProgressBlock;
}
在这个方法中同时调用了另一个方法 - [AFURLSessionManager setDelegate:forTask:]
来设置代理:
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
// 加锁
[self.lock lock];
// task 任务表示作为 key, delegate 作为 value
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 添加通知
[self addNotificationObserverForTask:task];
// 解锁
[self.lock unlock];
}
正如上面所提到的,AFURLSessionManager
就是通过字典 mutableTaskDelegatesKeyedByTaskIdentifier
来存储并管理每一个 NSURLSessionTask
,它以 taskIdentifier
为键存储 task
。
该方法使用 NSLock
来保证不同线程使用 mutableTaskDelegatesKeyedByTaskIdentifier
时,不会出现线程竞争的问题。
- addNotificationObserverForTask:task
用于给 task
添加通知, 用于处理 task
任务的暂停与恢复
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
// 恢复通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
// 暂停通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}
实现 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 {
// sessionDidBecomeInvalid 为自定义 block 块
self.sessionDidBecomeInvalid = block;
}
当代理方法调用时,如果存在对应的block
,会执行对应的block
:
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error{
// block 进行回调
if (self.sessionDidBecomeInvalid) {
self.sessionDidBecomeInvalid(session, error);
}
// 会话失效通知
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}
其他相似的接口实现和上述代码原理一致.
AFURLSessionManagerTaskDelegate 管理进度
在上面我们提到过 AFURLSessionManagerTaskDelegate
类,它主要为 task
提供进度管理功能(上传进度,下载进度),并在 task 结束时回调(completionHandler
);
我们看下AFURLSessionManagerTaskDelegate
是如何进行初始化的
// 通过 task初始化
- (instancetype)initWithTask:(NSURLSessionTask *)task {
self = [super init];
if (!self) {
return nil;
}
// 初始化实例对象
_mutableData = [NSMutableData data];
_uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
_downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
__weak __typeof__(task) weakTask = task;
for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]){
...略...
// KVO监听进度
[progress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
通过task
进行初始化, 在初始化方法中 初始化上传进度,下载进度
实例, 并注册通知用于监听进度
, 在监听方法内通过block
进行实时进度回调:
// 进度监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
// 监听 block 回调
if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
else if ([object isEqual:self.uploadProgress]) {
if (self.uploadProgressBlock) {
self.uploadProgressBlock(object);
}
}
}
通过 上传或下载
的代理方法,获取进度信息,下面以NSURLSessionDownloadDelegate
为例:
// NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
// 下载进度
self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
self.downloadProgress.completedUnitCount = totalBytesWritten;
}
当downloadProgress
的值发生改变,KVO
会进行监听,并在KVO
中进行Block
回调
代理方法 - URLSession: task: didCompleteWithError:
在每一个 NSURLSessionTask
结束时,都会在代理方法 - URLSession:task:didCompleteWithError:
中:
- 调用传入的 completionHander block
- 发出 AFNetworkingTaskDidCompleteNotification 通知
// NSURLSessionTaskDelegate -任务完成时调用
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
// 获取响应序列化器,存储到 userInfo 中
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
// 响应原始NSData数据
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
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
// 任务的原始响应数据,放入 userinfo
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
// 错误处理
if (error) {
// 任务相关的任何错误,放入 userinfo
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
// 如果当前 manager 持有 completionGroup 或者 completionQueue 就使用它们。否则会创建一个 dispatch_group_t 并在主线程中调用 completionHandler 并发送通知(在主线程中)。
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 {
// 无错误处理
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.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;
// 不连续数据
[self.mutableData appendData:data];
}
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
self.downloadFileURL = nil;
if (self.downloadTaskDidFinishDownloading) {
self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
if (self.downloadFileURL) {
NSError *fileManagerError = nil;
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&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
方法中进行的
+ (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
上对于NSURLSessionTask
的实现不同,所以会通过- [NSURLSession dataTaskWithURL:]
方法返回一个 NSURLSessionTask 实例 - 取得当前类
_AFURLSessionTaskSwizzling
中的实现af_resume
- 如果当前类
currentClass
有resume
方法- 真:5
- 假:6
- 使用
swizzleResumeAndSuspendMethodForClass:
调剂该类的resume
和suspend
方法 currentClass = [currentClass superclass]
4. Serialization(序列化)
请求以及响应的过程序列化
,主要涉及到两个模块:
- AFURLRequestSerialization
- AFURLResponseSerialization
其实在整个 AFNetworking
项目中并不存在这2个类,它们2个都是协议,遵守这2个协议会将数据序列化为我们指定方式的数据, AFURLRequestSerialization
负责生成 NSMutableURLRequest
,为请求设置 HTTP 头部,管理发出的请求,AFURLResponseSerialization
负责对返回的数据进行序列化, 后续有空会分析它们的源码及使用;
5. Security(保证请求的安全)
AFSecurityPolicy
是 AFNetworking
用来保证 HTTP
请求安全的类,它被 AFURLSessionManager
持有,如果你在 AFURLSessionManager
的实现文件中搜索 self.securityPolicy
,你只会得到三条结果:
- 初始化 self.securityPolicy = [AFSecurityPolicy defaultPolicy]
- 收到连接层的验证请求时
- 任务接收到验证请求时
在 API 调用上,后两者都调用了 - [AFSecurityPolicy evaluateServerTrust:forDomain:]
方法来判断当前服务器是否被信任,我们会在接下来的文章中具体介绍这个方法的实现的作用。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;
if (self.taskDidReceiveAuthenticationChallenge) {
disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
} else {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
disposition = NSURLSessionAuthChallengeUseCredential;
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
} else {
disposition = NSURLSessionAuthChallengeRejectProtectionSpace;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}
如果没有传入taskDidReceiveAuthenticationChallenge block
,只有在上述方法返回 YES
时,才会获得认证凭证 credential
。
6. Reachability(监控网络状态)
与 AFSecurityPolicy
相同,AFURLSessionManager
对网络状态的监控是由 AFNetworkReachabilityManager
来负责的,它仅仅是持有一个 AFNetworkReachabilityManager
的对象。
真正需要判断网络状态时,仍然需要开发者调用对应的 API 获取网络状态。
总结:
AFNetworking
实际上只是对 NSURLSession
高度地封装, 提供一些简单易用的 API
方便我们在 iOS 开发中发出网络请求并在其上更快地构建网络层组件并提供合理的接口;