该文章阅读的AFNetworking的版本为3.2.0。
完成了前面对AFURLRequestSerialization
、AFURLResponseSerialization
、AFSecurityPolicy
和AFNetworkReachabilityManager
类的阅读,接下来就可以阅读AFNetworking
的核心类AFURLSessionManager
啦。通过一开始对头文件的引用,就可以知道AFURLSessionManager
类的核心地位:
#import "AFURLResponseSerialization.h"#import "AFURLRequestSerialization.h"#import "AFSecurityPolicy.h"#if !TARGET_OS_WATCH#import "AFNetworkReachabilityManager.h"#endif复制代码
之前对上述类的阅读,就是为了给本类阅读做铺垫。
1.接口文件
1.1.属性
/** 网络会话管理者,属性是只读的。想要了解NSURLSession的使用可以看这篇文章:使用NSURLSession(https://www.jianshu.com/p/fafc67475c73) */@property (readonly, nonatomic, strong) NSURLSession *session;/** 操作队列,也是只读的,最大并发被设置为1,用于代理回调 */@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;/** 响应数据序列化对象,默认为`AFJSONResponseSerializer`,即处理json类型数据,不能设置为`nil` */@property (nonatomic, strong) idresponseSerializer;/** 用于确保安全连接的安全策略对象,默认为`defaultPolicy` */@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;/** 网络状况监控管理者,默认为`sharedManager` */@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;复制代码
- 获取Session的Tasks
/** 当前`session`创建的所有的任务,相当于下面三个属性的和 */@property (readonly, nonatomic, strong) NSArray*tasks;/** 当前`session`创建的所有的`dataTasks` */@property (readonly, nonatomic, strong) NSArray *dataTasks;/** 当前`session`创建的所有的`uploadTasks` */@property (readonly, nonatomic, strong) NSArray *uploadTasks;/** 当前`session`创建的所有的`downloadTasks` */@property (readonly, nonatomic, strong) NSArray *downloadTasks;复制代码
- 管理回调队列
/** 任务回调队列,默认或者为NULL时,就是在主队列 */@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;/** 任务回调组,默认或者为NULL时,就生成一个私有队列 */@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;复制代码
- 解决系统错误
/** 从iOS 7.0开始,创建后台上传任务有时候会返回为nil,如果设置为YES,AFNetworking遵循了苹果的建议,如果创建失败会重新创建,默认尝试三次。默认为NO */@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;复制代码
1.2.方法
- 初始化方法
/** 通过指定NSURLSessionConfiguration对象初始化对象 */- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;/** 当传YES,就立即关闭当前网络会话;当传NO,等待当前任务完成后再关闭当前对话 */- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;复制代码
- 创建NSURLSessionDataTask对象方法
/** 以指定的NSURLRequest对象创建NSURLSessionDataTask */- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;/** 以指定的NSURLRequest对象创建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对象方法
/** 以指定的NSURLRequest对象和要上传的本地文件的URL创建NSURLSessionUploadTask,同样,上传进度的回调是在子线程中 */- (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;/** 以指定的NSURLRequest对象和要上传的二进制类型数据创建NSURLSessionUploadTask,上传进度的回调也是在子线程中 */- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(nullable NSData *)bodyData progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;/** 以指定数据流的NSURLRequest对象创建NSURLSessionUploadTask,上传进度的回调也是在子线程中 */- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;复制代码
- 创建NSURLSessionDownloadTask对象方法
/** 以指定的NSURLRequest对象创建NSURLSessionDownloadTask,上传进度的回调是在子线程中,在下载的过程中会先将文件放到一个临时的路径targetPath,在下载完成后,会将文件移动到用户设置的路径上,并自动删除原路径上的文件。 但是,如果当初创建session的参数configuration设置的是后台模式的话,在应用被杀死时destination中的信息会丢失,所以最好在-setDownloadTaskDidFinishDownloadingBlock:方法中设置下载文件的保存路径 */- (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;/** 通过之前下载的数据创建NSURLSessionDownloadTask,恢复下载,其他的和上面的方法相同 */- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData 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;复制代码
- 获取Tasks进度方法
/** 获取指定task的上传进度 */- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;/** 获取指定task的下载进度 */- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;复制代码
- 设置NSURLSessionDelegate回调方法
/** 设置当session无效时的block回调,这个block回调用在NSURLSessionDelegate的方法URLSession:didBecomeInvalidWithError:中 */- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;/** 设置当session接收到验证请求时的block回调,这个block回调用在NSURLSessionDelegate的方法URLSession:didReceiveChallenge:completionHandler:中 */- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;复制代码
- 设置NSURLSessionTaskDelegate回调方法
/** 设置当task需要一个新的输入流时的block回调,这个block回调用在NSURLSessionTaskDelegate的方法URLSession:task:needNewBodyStream:中 */- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;/** 设置当一个HTTP请求试图执行重定向到一个不同的URL时的block回调,这个block回调用在NSURLSessionTaskDelegate的方法URLSession:willPerformHTTPRedirection:newRequest:completionHandler:中 */- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * _Nullable (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;/** 设置当task接收到身份验证时的block回调,这个block回调用在NSURLSessionTaskDelegate的方法URLSession:task:didReceiveChallenge:completionHandler:中 */- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;/** 设置一个block回调来定期跟踪上传进度,这个block回调用在NSURLSessionTaskDelegate的方法URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:中 */- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;/** 设置当task执行完成时的block回调,这个block回调用在NSURLSessionTaskDelegate的方法URLSession:task:didCompleteWithError:中 */- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;复制代码
- 设置NSURLSessionDataDelegate回调方法
/** 设置当dataTask接收到响应时的block回调,这个block回调用在NSURLSessionDataDelegate的方法URLSession:dataTask:didReceiveResponse:completionHandler:中 */- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;/** 设置当dataTask变成downloadTask时的block回调,这个block回调用在NSURLSessionDataDelegate的方法URLSession:dataTask:didBecomeDownloadTask:中 */- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;/** 设置当dataTask接收到数据时的block回调,这个block回调用在NSURLSessionDataDelegate的方法URLSession:dataTask:didReceiveData:中 */- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;/** 设置当dataTask将要对响应进行缓存时的block回调,这个block回调用在NSURLSessionDataDelegate的方法URLSession:dataTask:willCacheResponse:completionHandler:中 */- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;/** 设置当session队列中所有的消息都发送出去时的block回调,这个block回调用在NSURLSessionDataDelegate的方法URLSessionDidFinishEventsForBackgroundURLSession:中 */- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block;复制代码
- 设置NSURLSessionDownloadDelegate回调方法
/** 设置当downloadTask完成一个下载时的block回调,这个block回调用在NSURLSessionDownloadDelegate的方法URLSession:downloadTask:didFinishDownloadingToURL:中 */- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;/** 设置一个block回调来定期跟踪下载进度,这个block回调用在NSURLSessionDownloadDelegate的方法URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:中 */- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;/** 设置当downloadTask重新开始下载时的block回调,这个block回调用在NSURLSessionDownloadDelegate的方法URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:中 */- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;复制代码
1.3.全局静态常量
- 通知名称
/** 当一个task重新开始时就会发送这个通知 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification;/** 当一个task执行完成时就会发送这个通知 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteNotification;/** 当一个task暂停时就会发送这个通知 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidSuspendNotification;/** 当一个session无效时就会发送这个通知 */FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification;/** 当sessionDownloadTask将下载在临时路径的文件移动到用户指定路径出错时就是发送这个通知 */FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;复制代码
- 通知所传递的userInfo字典类型数据的key
/** 通过这个key可以从AFNetworkingTaskDidCompleteNotification通知所传递的userInfo字典类型数据中取出任务响应的原始数据 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;/** 如果响应已经序列化,通过这个key可以从AFNetworkingTaskDidCompleteNotification通知所传递的userInfo字典类型数据中取出任务响应的序列化数据 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;/** 如果响应序列化对象,通过这个key可以从AFNetworkingTaskDidCompleteNotification通知所传递的userInfo字典类型数据中取出任务响应序列化对象 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;/** 如果相应数据已经直接存储到磁盘,通过这个key可以从AFNetworkingTaskDidCompleteNotification通知所传递的userInfo字典类型数据中取出下载数据的存储路径 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;/** 如果存在错误,,通过这个key可以从AFNetworkingTaskDidCompleteNotification通知所传递的userInfo字典类型数据中取出与task或者是响应序列化相关的错误 */FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;复制代码
2.实现文件
2.1.宏定义
#ifndef NSFoundationVersionNumber_iOS_8_0#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11#else#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0#endif复制代码
这个宏通过NSFoundation
的版本来判断当前系统的版本,总之就是将NSFoundationVersionNumber_With_Fixed_5871104061079552_bug
定义为iOS8.0
2.2.静态方法
/** 创建一个单例串行队列,用于创建task */static dispatch_queue_t url_session_manager_creation_queue() { static dispatch_queue_t af_url_session_manager_creation_queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL); }); return af_url_session_manager_creation_queue;}/** 安全的创建一个任务,主要是为了兼容iOS8之前的系统bug,具体的原因在第一篇“AFNetworking源码阅读(一)——从使用入手”文章中有解释 */static void url_session_manager_create_task_safely(dispatch_block_t block) { if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) { // Fix of bug // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8) // Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093 dispatch_sync(url_session_manager_creation_queue(), block); } else { block(); }}/** 创建一个单利并发队列,用于处理返回的数据 */static dispatch_queue_t url_session_manager_processing_queue() { static dispatch_queue_t af_url_session_manager_processing_queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT); }); return af_url_session_manager_processing_queue;}/** 创建一个单利组,用于处理回调,用户可通过dispatch_group_notify实现对回调完成的监控 */static dispatch_group_t url_session_manager_completion_group() { static dispatch_group_t af_url_session_manager_completion_group; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ af_url_session_manager_completion_group = dispatch_group_create(); }); return af_url_session_manager_completion_group;}复制代码
2.3.全局静态常量
- 这些是对.h文件中全局静态常量进行赋值
NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete";NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";复制代码
- 为锁对象命名
static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";复制代码
- 这个就是在
.h
文件解释属性attemptsToRecreateUploadTasksForBackgroundSessions中提到的尝试三次
static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;复制代码
2.4.别名
- 这些都是为
.h
文件中设置的回调方法中为接收传入的block起的别名
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request);typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session);typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task);typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error);typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response);typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask);typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data);typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse);typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);复制代码
- 这个为进度回调block起的别名
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);复制代码
- 这个为完成回调block起的别名
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);复制代码
2.5.AFURLSessionManagerTaskDelegate私有类
2.5.1.接口
- 属性
/** 网路会话管理者,为了防止循环引用这里用了weak */@property (nonatomic, weak) AFURLSessionManager *manager;/** 保存接收到的数据 */@property (nonatomic, strong) NSMutableData *mutableData;/** 上传进度 */@property (nonatomic, strong) NSProgress *uploadProgress;/** 下载进度 */@property (nonatomic, strong) NSProgress *downloadProgress;/** 下载保存路径 */@property (nonatomic, copy) NSURL *downloadFileURL;/** 保存下载完成回调block */@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;/** 保存上传进度回调block */@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;/** 保存下载进度回调block */@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;/** 保存任务完成回调block */@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;复制代码
- 方法
/** 以指定NSURLSessionTask对象初始化方法 */- (instancetype)initWithTask:(NSURLSessionTask *)task;复制代码
2.5.2.实现
- 生命周期方法
- (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]; // 将传入的task的取消、暂停和重启与进度对象相应的操作进行绑定 __weak __typeof__(task) weakTask = task; for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]) { progress.totalUnitCount = NSURLSessionTransferSizeUnknown; progress.cancellable = YES; progress.cancellationHandler = ^{ [weakTask cancel]; }; progress.pausable = YES; progress.pausingHandler = ^{ [weakTask suspend]; };#if __has_warning("-Wunguarded-availability-new") if (@available(iOS 9, macOS 10.11, *)) {#else if ([progress respondsToSelector:@selector(setResumingHandler:)]) {#endif progress.resumingHandler = ^{ [weakTask resume]; }; } // 观察进度对象的进度 [progress addObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew context:NULL]; } return self;}- (void)dealloc { // 移除进度对象的观察 [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))]; [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];}复制代码
- KVO方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)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); } }}复制代码
- NSURLSessionTaskDelegate方法实现
/** 当`NSURLSessionTaskDelegate`的这个方法被调用时,意味着这个`task`已经执行完成,无论是否出错 */- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error{ // 因为self.manager属性关键字是weak,所以为了防止被释放就用__strong __strong AFURLSessionManager *manager = self.manager; // 用来保存请求返回的数据,为了可以在block中进行修改,用了__block __block id responseObject = nil; // 用来保存发送通知时传递的数据,为了可以在block中进行修改,用了__block,并进行赋值 __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; } // 如果请求出错 if (error) { // 传递错误信息 userInfo[AFNetworkingTaskDidCompleteErrorKey] = error; // 用户可以自定义调度组和队列并利用dispatch_group_notify实现对回调完成的监控 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]; }); }); }); }}复制代码
- NSURLSessionDataDelegate方法实现
/** 当`NSURLSessionDataDelegate`的这个方法被调用时,意味着已经接收到服务器返回的数据了 */- (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];}/** 当`NSURLSessionDataDelegate`的这个方法被调用时,意味着已经向服务器上传了数据 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSenttotalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ // 更新上传进度对象的属性 self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend; self.uploadProgress.completedUnitCount = task.countOfBytesSent;}复制代码
- NSURLSessionDownloadDelegate方法实现
/** 当执行下载任务时,`NSURLSessionDownloadDelegate`的这个方法会定期调用,传递当前下载进度 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ // 更新下载进度对象的属性 self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite; self.downloadProgress.completedUnitCount = totalBytesWritten;}/** 当`NSURLSessionDataDelegate`的这个方法被调用时,表示下载已重启 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffsetexpectedTotalBytes:(int64_t)expectedTotalBytes{ // 更新下载进度对象的属性 self.downloadProgress.totalUnitCount = expectedTotalBytes; self.downloadProgress.completedUnitCount = fileOffset;}/** 当`NSURLSessionDataDelegate`的这个方法被调用时,表示已完成下载 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(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]; } } }}复制代码
由此,可以看出AFURLSessionManagerTaskDelegate
这个类主要是用来监控上传与下载的进度,以及对task
完成后数据的处理和回调。
2.6._AFURLSessionTaskSwizzling私有类
2.6.1.静态方法
/** 交换某个类两个方法的实现 */static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) { Method originalMethod = class_getInstanceMethod(theClass, originalSelector); Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector); method_exchangeImplementations(originalMethod, swizzledMethod);}/** 给一个类添加一个方法 */static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) { return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));}复制代码
2.6.2.静态常量
/** 当一个task重新开始时就会发送这个通知 */static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume";/** 当一个task暂停时就会发送这个通知 */static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofire.networking.nsurlsessiontask.suspend";复制代码
2.6.3.方法实现
+ (void)load { /** WARNING: Trouble Ahead https://github.com/AFNetworking/AFNetworking/pull/2702 */ // 判断是否有NSURLSessionTask这个类 if (NSClassFromString(@"NSURLSessionTask")) { /** NSURLSessionTask的实现在iOS 7和iOS 8中有所不同,这使得下面代码实现起来有些棘手。 已经做了许多单元测试来验证这个方法的可行性。 目前我们所知道的是: - NSURLSessionTasks是通过类簇设计模式实现的,这就意味着你通过这个类提供的接口获得的类并不是这个类。 - 简单的通过 ‘[NSURLSessionTask class]’ 方法并不起作用,你需要通过NSURLSession创建一个task,才能获取它所在的类。 - 在iOS 7中,‘localDataTask’是的类型是‘__NSCFLocalDataTask’,它的继承关系是:__NSCFLocalDataTask -> __NSCFLocalSessionTask -> __NSCFURLSessionTask。 - 在iOS 8中,‘localDataTask’是的类型是‘__NSCFLocalDataTask’,它的继承关系是:__NSCFLocalDataTask -> __NSCFLocalSessionTask -> NSURLSessionTask。 - 在iOS 7中,只有‘__NSCFLocalSessionTask’和其父类‘__NSCFURLSessionTask’这两个类实现了它们的‘resume’和‘suspend’方法,并且在方法实现里‘__NSCFLocalSessionTask’类并没有调用其父类的方法,这就意味着两个类都要进行方法交换。 - 在iOS 8中,只有‘NSURLSessionTask’类实现了‘resume’和‘suspend’方法,这就意味着只对该类进行方法交换即可。 - 因为‘NSURLSessionTask’类并不是在每个iOS的版本中都存在,所有在这个虚构类里可以更容易添加和管理交换方法 一些假设前提: - ‘resume’和‘suspend’方法在实现时,并没有调用其父类的实现方法。但如果在以后的iOS版本中调用了其父类的实现方法,我们还要再进行处理。 - ‘resume’和‘suspend’方法不会被其他类复写 目前的解决方案: 1) 先通过‘NSURLSession’实例化一个dataTask对象,再通过dataTask对象获取‘__NSCFLocalDataTask’对象。 2) 获取指向‘af_resume’方法原始实现的指针。 3) 检查当前类是否实现了resume方法,如果实现了就继续执行第4步 4) 获取当前类的父类 5) 获取当前类指向‘resume’方法实现的指针。 6) 获取当前类的父类指向‘resume’方法实现的指针。 7) 如果当前类和其父类指向‘resume’方法实现的指针不一致,并且当前类指向‘resume’方法实现的指针和指向‘af_resume’方法原始实现的指针也不一致,就进行方法交换 8) 然后再通过步骤3-8检查其父类 */ // 实例化网络会话配置对象 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 // 获取指向当前类的af_resume方法原始实现的指针 IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume))); // 获取网络会话任务对象的具体类 Class currentClass = [localDataTask class]; // 如果这个具体类实现了resume方法则进入循环体 while (class_getInstanceMethod(currentClass, @selector(resume))) { // 获取这个具体类的父类 Class superClass = [currentClass superclass]; // 获取指向这个具体类的resume方法实现的指针 IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume))); // 获取指向这个具体类的父类的resume方法实现的指针 IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume))); // 如果指向这个具体类的resume方法实现的指针,和指向其的父类的resume方法实现的指针,以及指向当前类的af_resume方法原始实现的指针,都不一致 if (classResumeIMP != superclassResumeIMP && originalAFResumeIMP != classResumeIMP) { // 向当前这个具体类添加af_resume和af_suspend方法,并与其resume和suspend方法作交换 [self swizzleResumeAndSuspendMethodForClass:currentClass]; } // 获取当前这个具体类的父类,继续循环判断其父类 currentClass = [currentClass superclass]; } // 取消这个网络会话任务 [localDataTask cancel]; // 立即结束这个网络会话 [session finishTasksAndInvalidate]; }}/** 为一个了动态添加af_resume和af_suspend方法,并与之对应的resume和suspend做交换 */+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass { // 获取本类的af_resume和af_suspend方法 Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume)); Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend)); // 如果想目标类中成功添加了af_resume方法 if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) { // 交换目标类的resume和af_resume方法 af_swizzleSelector(theClass, @selector(resume), @selector(af_resume)); } // 如果想目标类中成功添加了af_suspend方法 if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) { // 交换目标类的suspend和af_suspend方法 af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend)); }}- (NSURLSessionTaskState)state { NSAssert(NO, @"State method should never be called in the actual dummy class"); return NSURLSessionTaskStateCanceling;}- (void)af_resume { // 获取NSURLSessionDataTask对象的state属性,并调用其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 { // 获取NSURLSessionDataTask对象的state属性,并调用其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]; }}复制代码
读完这个私有类后,发现一个问题:就是_AFURLSessionTaskSwizzling
并没有被调用,甚至没有出现在其他代码的任何一个地方,这就很奇怪。既然没有调用,写了这么一大堆代码是怎么起作用的呢?经过查阅资料发现:当类被引用进项目的时候就会执行load函数(在main函数开始执行之前),与这个类是否被用到无关,每个类的load函数只会自动调用一次。
要是想要进一步了解有关load方法的话,可以看这篇文章:,如果想要深入了解的话可以看这篇文章:
2.7.类扩展
/** 保存网络会话配置对象 */@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;/** 保存回调操作队列对象 */@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;/** 保存网络会话对象 */@property (readwrite, nonatomic, strong) NSURLSession *session;/** 保存AFURLSessionManagerTaskDelegate对象和task之间的联系 */@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;/** 保存task的taskDescription属性值,在代码中被设置成当前对象的地址值 */@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;/** 保存锁对象,这个锁用来保证对mutableTaskDelegatesKeyedByTaskIdentifier存取的线程安全 */@property (readwrite, nonatomic, strong) NSLock *lock;/** 保存session无效时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;/** 保存session接收到验证请求时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;/** 保存session队列中所有的消息都发送出去时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;/** 保存一个HTTP请求试图执行重定向到一个不同的URL时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;/** 保存task接收到身份验证时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;/** 保存task需要一个新的输入流时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;/** 保存一个来定期跟踪上传进度的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;/** 保存task执行完成时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;/** 保存dataTask接收到响应时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;/** 保存dataTask变成downloadTask时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;/** 保存dataTask接收到数据时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;/** 保存dataTask将要对响应进行缓存时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;/** 保存downloadTask完成一个下载时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;/** 保存一个来定期跟踪下载进度的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;/** 保存downloadTask重新开始下载时的block回调 */@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;复制代码
2.8.方法实现
- 生命周期方法
- (instancetype)init { // 默认配置初始化 return [self initWithSessionConfiguration:nil];}- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { self = [super init]; if (!self) { return nil; } // 如果没有传入配置对象就使用默认网络会话配置 if (!configuration) { configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; } self.sessionConfiguration = configuration; // 实例化一个操作队列并设置最大并发数为1 self.operationQueue = [[NSOperationQueue alloc] init]; self.operationQueue.maxConcurrentOperationCount = 1; // 通过上面生成的两个对象实例化网络会话对象 self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; // 默认响应序列化对象是序列化json数据对象 self.responseSerializer = [AFJSONResponseSerializer serializer]; // 默认的安全策略是默认安全策略 self.securityPolicy = [AFSecurityPolicy defaultPolicy]; // 实例化网络状态监测对象#if !TARGET_OS_WATCH self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];#endif // 实例化可变字典关联task和其AFURLSessionManagerTaskDelegate对象,使其一一对应 self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init]; // 实例化锁对象,确保上面的可变字典存取线程安全 self.lock = [[NSLock alloc] init]; self.lock.name = AFURLSessionManagerLockName; // 异步的获取当前session的所有未完成的task,并进行置空处理,主要是为了从后台切换到前台时重新初始化session [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;}- (void)dealloc { // 移除通知观察者 [[NSNotificationCenter defaultCenter] removeObserver:self];}复制代码
- 懒加载方法
/** 获取当前AFURLSessionManager对象的地址字符串赋值给task的taskDescription属性,目的是通过这个字符串来判断通知监听到的是否是当前AFURLSessionManager对象所拥有的task发出的 */- (NSString *)taskDescriptionForSessionTasks { return [NSString stringWithFormat:@"%p", self];}复制代码
- 通知响应方法
/** 当task已经重启的时候会通过通知调用这个方法 */- (void)taskDidResume:(NSNotification *)notification { // 从通知对象中获取到发送这条通知的task NSURLSessionTask *task = notification.object; // 如果这个task属于这个AFURLSessionManager对象 if ([task respondsToSelector:@selector(taskDescription)]) { if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) { // 主线程异步发送通知task已经重启 dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task]; }); } }}/** 当task已经暂停的时候会通过通知调用这个方法 */- (void)taskDidSuspend:(NSNotification *)notification { // 从通知对象中获取到发送通知的task NSURLSessionTask *task = notification.object; // 如果这个task属于这个AFURLSessionManager对象 if ([task respondsToSelector:@selector(taskDescription)]) { if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) { dispatch_async(dispatch_get_main_queue(), ^{ // 主线程异步发送通知task已经暂停 [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task]; }); } }}复制代码
- 处理AFURLSessionManagerTaskDelegate对象和NSURLSessionTask对象关系的私有方法
/** 通过task对象获取其绑定的AFURLSessionManagerTaskDelegate对象 */- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task { // 在debug下,缺少task参数就crash NSParameterAssert(task); // 在线程安全的环境下,通过task的taskIdentifier属性,从mutableTaskDelegatesKeyedByTaskIdentifier属性中获取绑定的delegate AFURLSessionManagerTaskDelegate *delegate = nil; [self.lock lock]; delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)]; [self.lock unlock]; return delegate;}/** 为task绑定delegate */- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate forTask:(NSURLSessionTask *)task{ // 在debug下,缺少参数就crash NSParameterAssert(task); NSParameterAssert(delegate); // 在线程安全的环境下 [self.lock lock]; // 以task的taskIdentifier属性为key,以delegate为value,保存到mutableTaskDelegatesKeyedByTaskIdentifier属性中。 self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate; // 添加通知监听task的重启和暂停事件 [self addNotificationObserverForTask:task]; [self.lock unlock];}/** 为dataTask绑定delegate */- (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{ // 通过dataTask实例化delegate对象,并初始化属性 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask]; delegate.manager = self; delegate.completionHandler = completionHandler; // 标记dataTask所属的AFURLSessionManager对象 dataTask.taskDescription = self.taskDescriptionForSessionTasks; // 为dataTask绑定delegate [self setDelegate:delegate forTask:dataTask]; delegate.uploadProgressBlock = uploadProgressBlock; delegate.downloadProgressBlock = downloadProgressBlock;}/** 为uploadTask绑定delegate */- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ // 通过uploadTask实例化delegate对象,并初始化属性 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask]; delegate.manager = self; delegate.completionHandler = completionHandler; // 标记uploadTask所属的AFURLSessionManager对象 uploadTask.taskDescription = self.taskDescriptionForSessionTasks; // 为uploadTask绑定delegate [self setDelegate:delegate forTask:uploadTask]; delegate.uploadProgressBlock = uploadProgressBlock;}/** 为downloadTask绑定delegate */- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler{ // 通过downloadTask实例化delegate对象,并初始化属性 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask]; delegate.manager = self; delegate.completionHandler = completionHandler; // 如果设置了保存下载文件的路径,就赋值给delegate if (destination) { delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) { return destination(location, task.response); }; } // 标记downloadTask所属的AFURLSessionManager对象 downloadTask.taskDescription = self.taskDescriptionForSessionTasks; // 为downloadTask绑定delegate [self setDelegate:delegate forTask:downloadTask]; delegate.downloadProgressBlock = downloadProgressBlock;}/** 移除task绑定的delegate */- (void)removeDelegateForTask:(NSURLSessionTask *)task { // 在debug下,缺少参数就crash NSParameterAssert(task); // 在线程安全的环境下 [self.lock lock]; // 移除对task观察的通知 [self removeNotificationObserverForTask:task]; // 从mutableTaskDelegatesKeyedByTaskIdentifier移除task [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)]; [self.lock unlock];}复制代码
- 公共接口获取task相关属性的get方法
/** 通过传入的不同类型task的名称获取相应的tasks */- (NSArray *)tasksForKeyPath:(NSString *)keyPath { // 创建临时变量保存获取到的tasks __block NSArray *tasks = nil; // 创建信号量,因为getTasksWithCompletionHandler这个方法是异步获取tasks,为了避免还没获取到tasks就返回,就使用信号量进行控制 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { // 根据传入的不同类型task的名称获取相应的tasks if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) { tasks = dataTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) { tasks = uploadTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) { tasks = downloadTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) { // 利用valueForKeyPath合并数组并保留重复值 tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"]; } // 发送一个信号量,使semaphore变为1,表示已经获取到tasks,可以向下执行 dispatch_semaphore_signal(semaphore); }]; // 等待信号量变为1 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); return tasks;}/** 获取当前AFURLSessionManager对象的所有tasks */- (NSArray *)tasks { return [self tasksForKeyPath:NSStringFromSelector(_cmd)];}/** 获取当前AFURLSessionManager对象的所有dataTasks */- (NSArray *)dataTasks { return [self tasksForKeyPath:NSStringFromSelector(_cmd)];}/** 获取当前AFURLSessionManager对象的所有uploadTasks */- (NSArray *)uploadTasks { return [self tasksForKeyPath:NSStringFromSelector(_cmd)];}/** 获取当前AFURLSessionManager对象的所有downloadTasks */- (NSArray *)downloadTasks { return [self tasksForKeyPath:NSStringFromSelector(_cmd)];}复制代码
通过tasksForKeyPath:
方法的实现,我们可以学到如何利用GCD的信号量将异步回调转换为同步执行
- 公共接口结束网络会话方法
/** 当传YES,就立即关闭当前网络会话;当传NO,等待当前任务完成后再关闭当前对话 */- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks { if (cancelPendingTasks) { [self.session invalidateAndCancel]; } else { [self.session finishTasksAndInvalidate]; }}复制代码
- 公共接口设置responseSerializer相关属性的set方法
- (void)setResponseSerializer:(id)responseSerializer { // 在debug下,缺少参数就crash NSParameterAssert(responseSerializer); // 保存设置的参数 _responseSerializer = responseSerializer;}复制代码
- 处理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];}/** 移除task的观察通知 */- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task { [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];}复制代码
在之前看过的那个私有类_AFURLSessionTaskSwizzling
中,AFNetworking
交换了task
的resume
和suspend
方法。
以resume
方法为例说明其内部实现,当调用task
的resume
方法时,实际上调用的是af_resume
方法。
在af_resume
方法中,又调用了af_resume
方法,实际上调用的是系统的resume
方法,同时发送了通知AFNSURLSessionTaskDidResumeNotification
。
当前AFURLSessionManager
对象通过观察接收到通知后,就调用taskDidResume:
方法。
在taskDidResume:
方法中判断触发的resume
方法是当前AFURLSessionManager
对象所持有的task
后,在主线程异步发送AFNetworkingTaskDidResumeNotification
通知,告诉外界这个task
重启了。
通过这一系列的处理,可以看出AFNetworking
想要实现的,其实就是想在原来方法的功能上,添加向外发送通知功能,已达到监听的目的。只不过由于苹果在不同系统版本上对NSURLSessionTask
这个类的内部实现不同,以及类簇的设计模式,导致了实现起来“a bit tricky”
- 创建NSURLSessionDataTask对象的公共方法
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ // 调用下面的方法 return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];}- (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 { // 安全的通过传入的request创建一个dataTask __block NSURLSessionDataTask *dataTask = nil; url_session_manager_create_task_safely(^{ dataTask = [self.session dataTaskWithRequest:request]; }); // 为dataTask绑定AFURLSessionManagerTaskDelegate对象,以监听dataTask的处理进度和处理数据 [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler]; return dataTask;}复制代码
- 创建NSURLSessionUploadTask对象的公共方法
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ // 安全的通过传入的request和fileURL创建一个uploadTask __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; // 在iOS7上可能会创建失败 // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113) // 如果没有创建成功,且允许重新创建,且NSURLSessionConfiguration对象是通过backgroundSessionConfigurationWithIdentifier:方法创建的,就重复尝试三次 if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) { uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; } } }); // 为uploadTask绑定AFURLSessionManagerTaskDelegate对象,以监听uploadTask的处理进度和处理数据 if (uploadTask) { [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; } return uploadTask;}- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ // 安全的通过传入的request和bodyData创建一个uploadTask __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData]; }); // 为uploadTask绑定AFURLSessionManagerTaskDelegate对象,以监听uploadTask的处理进度和处理数据 [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; return uploadTask;}- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ // 安全的通过传入的request创建一个uploadTask __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ uploadTask = [self.session uploadTaskWithStreamedRequest:request]; }); // 为uploadTask绑定AFURLSessionManagerTaskDelegate对象,以监听uploadTask的处理进度和处理数据 [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; return uploadTask;}复制代码
- 创建NSURLSessionDownloadTask对象的公共方法
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler{ // 安全的通过传入的request创建一个downloadTask __block NSURLSessionDownloadTask *downloadTask = nil; url_session_manager_create_task_safely(^{ downloadTask = [self.session downloadTaskWithRequest:request]; }); // 为downloadTask绑定AFURLSessionManagerTaskDelegate对象,以监听downloadTask的处理进度和处理数据 [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler]; return downloadTask;}- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler{ // 安全的通过传入的resumeData重启一个downloadTask __block NSURLSessionDownloadTask *downloadTask = nil; url_session_manager_create_task_safely(^{ downloadTask = [self.session downloadTaskWithResumeData:resumeData]; }); // 为downloadTask绑定AFURLSessionManagerTaskDelegate对象,以监听downloadTask的处理进度和处理数据 [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler]; return downloadTask;}复制代码
- 获取tasks进度方法的公共方法
- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task { return [[self delegateForTask:task] uploadProgress];}- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task { return [[self delegateForTask:task] downloadProgress];}复制代码
这两个方法都是先通过传入的task
参数获取到与之绑定的AFURLSessionManagerTaskDelegate
对象,再通过AFURLSessionManagerTaskDelegate
对象获取其监听的进度数据
- 设置NSURLSessionDelegate回调的公共方法
- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block { self.sessionDidBecomeInvalid = block;}- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { self.sessionDidReceiveAuthenticationChallenge = block;}复制代码
- 设置NSURLSessionTaskDelegate回调的公共方法
- (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block { self.taskNeedNewBodyStream = block;}- (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block { self.taskWillPerformHTTPRedirection = block;}- (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { self.taskDidReceiveAuthenticationChallenge = block;}- (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block { self.taskDidSendBodyData = block;}- (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block { self.taskDidComplete = block;}复制代码
- 设置NSURLSessionDataDelegate回调的公共方法
- (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block { self.dataTaskDidReceiveResponse = block;}- (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block { self.dataTaskDidBecomeDownloadTask = block;}- (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block { self.dataTaskDidReceiveData = block;}- (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block { self.dataTaskWillCacheResponse = block;}- (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block { self.didFinishEventsForBackgroundURLSession = block;}复制代码
- 设置NSURLSessionDownloadDelegate回调的公共方法
- (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block { self.downloadTaskDidFinishDownloading = block;}- (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block { self.downloadTaskDidWriteData = block;}- (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block { self.downloadTaskDidResume = block;}复制代码
- NSObject方法
- (NSString *)description { // 定制打印数据 return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue];}- (BOOL)respondsToSelector:(SEL)selector { // 如果没有对相应的block进行赋值,也不会去调用实现相应的代理 if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) { return self.taskWillPerformHTTPRedirection != nil; } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) { return self.dataTaskDidReceiveResponse != nil; } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) { return self.dataTaskWillCacheResponse != nil; } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) { return self.didFinishEventsForBackgroundURLSession != nil; } return [[self class] instancesRespondToSelector:selector];}复制代码
- NSURLSessionDelegate方法实现
/** 当session无效时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)sessiondidBecomeInvalidWithError:(NSError *)error{ // 调用block回调数据 if (self.sessionDidBecomeInvalid) { self.sessionDidBecomeInvalid(session, error); } // 发送通知 [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];}/** 当session接收到验证请求时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)sessiondidReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{ // 设置临时变量保存数据 NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __block NSURLCredential *credential = nil; // 如果通过block回调传入了证书处理方式,则直接传参 if (self.sessionDidReceiveAuthenticationChallenge) { disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential); // 如果没有传入证书处理方式 } else { // 如果验证方式为NSURLAuthenticationMethodServerTrust 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; } // 如果验证方式不是NSURLAuthenticationMethodServerTrust,也使用默认方式验证证书 } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } } // 回调结果 if (completionHandler) { completionHandler(disposition, credential); }}复制代码
- NSURLSessionTaskDelegate方法实现
/** 当一个HTTP请求试图执行重定向到一个不同的URL时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskwillPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler{ NSURLRequest *redirectRequest = request; // 如果通过block传入重定向的处理方式,就传参调用 if (self.taskWillPerformHTTPRedirection) { redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request); } // 回调结果 if (completionHandler) { completionHandler(redirectRequest); }}/** 当task接收到身份验证时,会调用这个代理方法。这个证书验证的处理方式和上面那个一模一样,只不过上面那个是session级别的,这个是task级别的 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{ // 设置临时变量保存数据 NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __block NSURLCredential *credential = nil; // 如果通过block传入了证书处理方式,则直接传参调用 if (self.taskDidReceiveAuthenticationChallenge) { disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential); // 如果没有传入证书处理方式 } else { // 如果验证方式为NSURLAuthenticationMethodServerTrust 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 = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } // 如果验证方式不是NSURLAuthenticationMethodServerTrust,就使用默认方式验证证书 } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } } // 回调结果 if (completionHandler) { completionHandler(disposition, credential); }}/** 当task需要一个新的输入流时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler{ // 创建临时变量保存数据 NSInputStream *inputStream = nil; // 如果通过block回调传入获取输入流的方式,就传参调用 if (self.taskNeedNewBodyStream) { inputStream = self.taskNeedNewBodyStream(session, task); // 否则如果task中原有输入流,就用原有输入流 } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) { inputStream = [task.originalRequest.HTTPBodyStream copy]; } // 回调结果 if (completionHandler) { completionHandler(inputStream); }}/** 当task已经发送出数据时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSenttotalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ // 创建临时变量保存数据 int64_t totalUnitCount = totalBytesExpectedToSend; // 如果数据总大小获取失败 if(totalUnitCount == NSURLSessionTransferSizeUnknown) { // 通过请求头中的“Content-Length”字段获取大小 NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"]; if(contentLength) { totalUnitCount = (int64_t) [contentLength longLongValue]; } } // 获取与task绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; // 调用delegate对象所实现相同的代理方法来监听进度 if (delegate) { [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend]; } // 调用block回调数据 if (self.taskDidSendBodyData) { self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount); }}/** 当task执行完成时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error{ // 获取与task绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; // 加判断的原因是,在后台结束这个task时,其delegate可能会被置nil // delegate may be nil when completing a task in the background if (delegate) { // 调用delegate对象所实现相同的代理方法来处理结果 [delegate URLSession:session task:task didCompleteWithError:error]; // 移除对task监听的通知和其绑定的delegate [self removeDelegateForTask:task]; } // 调用block回调数据 if (self.taskDidComplete) { self.taskDidComplete(session, task, error); }}复制代码
- NSURLSessionDataDelegate方法实现
/** 当dataTask接收到响应时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTaskdidReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{ // 创建临时变量保存接收到数据后的处理模式 NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow; // 如果通过block传入了处理方式,则传参调用 if (self.dataTaskDidReceiveResponse) { disposition = self.dataTaskDidReceiveResponse(session, dataTask, response); } // 回调结果 if (completionHandler) { completionHandler(disposition); }}/** 当dataTask变成downloadTask时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTaskdidBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{ // 获取与dataTask绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; if (delegate) { // 把delegate从dataTask上解绑,然后绑定到downloadTask [self removeDelegateForTask:dataTask]; [self setDelegate:delegate forTask:downloadTask]; } // 调用block回调数据 if (self.dataTaskDidBecomeDownloadTask) { self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask); }}/** 当dataTask接收到数据时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ // 获取与dataTask绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; // 调用delegate对象所实现相同的代理方法来处理结果 [delegate URLSession:session dataTask:dataTask didReceiveData:data]; // 调用block回调数据 if (self.dataTaskDidReceiveData) { self.dataTaskDidReceiveData(session, dataTask, data); }}/** 当dataTask将要对响应进行缓存时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler{ // 创建临时变量保存要缓存的相应对象 NSCachedURLResponse *cachedResponse = proposedResponse; // 如果通过block传入了处理方式,则传参调用 if (self.dataTaskWillCacheResponse) { cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse); } // 回调结果 if (completionHandler) { completionHandler(cachedResponse); }}/** 当session队列中所有的消息都发送出去时,会调用这个代理方法 */- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { // 主队列异步回调结果 if (self.didFinishEventsForBackgroundURLSession) { dispatch_async(dispatch_get_main_queue(), ^{ self.didFinishEventsForBackgroundURLSession(session); }); }}复制代码
- NSURLSessionDownloadDelegate方法实现
/** 当downloadTask完成一个下载时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location{ // 获取与downloadTask绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; // 如果通过block传入了处理方式 if (self.downloadTaskDidFinishDownloading) { // 则传参调用获取下载文件保存路径 NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); if (fileURL) { delegate.downloadFileURL = fileURL; NSError *error = nil; // 移动文件,如果出错则发送通知,传递数据 if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) { [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo]; } return; } } // 调用delegate对象所实现相同的代理方法来处理结果 if (delegate) { [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; }}/** downloadTask下载时的定期回调代理 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ // 获取与downloadTask绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; // 调用delegate对象所实现相同的代理方法来处理数据 if (delegate) { [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; } // 调用block回调数据 if (self.downloadTaskDidWriteData) { self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); }}/** 当downloadTask重新开始下载时,会调用这个代理方法 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffsetexpectedTotalBytes:(int64_t)expectedTotalBytes{ // 获取与downloadTask绑定的delegate对象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; // 调用delegate对象所实现相同的代理方法来处理数据 if (delegate) { [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes]; } // 调用block回调数据 if (self.downloadTaskDidResume) { self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes); }}复制代码
- NSSecureCoding方法实现
+ (BOOL)supportsSecureCoding { return YES;}- (instancetype)initWithCoder:(NSCoder *)decoder { NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; self = [self initWithSessionConfiguration:configuration]; if (!self) { return nil; } return self;}- (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];}复制代码
关于NSSecureCoding
代理方法的实现在这篇文章中的4.1.2.4.7 NSSecureCoding协议方法的实现段落已经介绍过。
- NSCopying方法实现
- (instancetype)copyWithZone:(NSZone *)zone { return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];}复制代码
3.总结
到这里,AFURLSessionManager
这个类我们就看完了。可以看出该类是负责管理NSURLSession
对象,创建各种类型的task
,并监听其属性的状态,处理代理和返回的数据。
源码阅读系列:AFNetworking