作为一个老资历的程序员,优秀的第三方的源码早就开始研究了,但是研究过后就丢在了一边,一直没有整理,最近终于有空了,整理下AFN的源码,加上标注和自己的理解。
- AFURLSessionManagerTaskDelegate
@property (nonatomic, weak) AFURLSessionManager *manager;//任务代理的manager A
@property (nonatomic, strong) NSMutableData *mutableData;
@property (nonatomic, strong) NSProgress *uploadProgress;//上传进度对象
@property (nonatomic, strong) NSProgress *downloadProgress;//下载进度对象
@property (nonatomic, copy) NSURL *downloadFileURL;//下载文件的URL
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
//初始化
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.mutableData = [NSMutableData data];
//初始化上传下载进度对象和对象的总量
self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
return self;
}
- (void)setupProgressForTask:(NSURLSessionTask *)task{
为任务设置上传进度和下载进度,并添加开始、取消、继续的回调
为任务添加观察者,观察任务的属性值得变化,主要针对的是上传、下载数据量的变化
为上传进度对象、下载进度对象添加观察者,针对的是进度对象的变化,并实时回调
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {//如果是任务类或者下载任务类
//动态设置进度对象的变化、
//观察任务的属性
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] 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);
}
}
}
//移除任务的观察者,移除进度对象的观察者
- (void)cleanUpProgressForTask:(NSURLSessionTask *)task
系统的三个代理方法,处理网络请求的结束、已接收的数据的拼接、下载任务的完成
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
//dispatch_group调度组 queue提交闭包函数的Block
//就是一个队列组,线程里面任务结束会发出一个消息 主要的目的我估计就是为了任务完成的时候可以接收到相应的通知
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];
});
});
如果请求无错误:会解析返回的数据
成功、失败都会执行上面的代码进行回调和通知
//接受数据的过程,拼接数据
1. (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
//完成文件的下载
2. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
- AFURLSessionManager
初始化AFURLSessionManager,配置manager的属性:session配置、operationQueue发送请求队列、配置session、设置默认通信信息解析策略属性、默认安全策略属性、通信监听属性、属性锁
@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
@property (readwrite, nonatomic, strong) NSURLSession *session;
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
@property (readwrite, nonatomic, strong) NSLock *lock;
- (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;
//设置session配置、代理和代理队列
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
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
//初始化锁
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
//获取session的任务数组, 重置任务,按理说初始化的时候这些任务数组都是空的,但是也有初始化之前的请求任务 目的:避免初始化的时候以前后台的请求任务,导致的程序Crash
[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;
}
//获取对应路径的keyPath
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
__block NSArray *tasks = nil;
//创建信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//回调
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
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))]) {
tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
}
//回调里的操作全部执行任务 发送信号
dispatch_semaphore_signal(semaphore);
}];
//等待信号返回,保证回调执行完毕能够获取到对应的tasks
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return tasks;
}
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
//设置默认的处理方式 默认的处理方式会忽略credential参数
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;
// 调动自身的处理方法,也就是说我们通过sessionDidReceiveAuthenticationChallenge这个block接收session,challenge 参数,返回一个NSURLSessionAuthChallengeDisposition结果,这个业务使我们自己在这个block中完成。
if (self.sessionDidReceiveAuthenticationChallenge) {//如果实现了自定义验证方法
disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
} else {// 如果没有实现自定义的验证过程
// 判断challenge的authenticationMethod
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
// 使用安全策略来验证
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {//验证服务器
// 如果验证通过,根据serverTrust创建依据
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {// 有的话就返回UseCredential
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else { // 验证没通过,返回CancelAuthenticationChallenge
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
if (completionHandler) {//回调返回验证方式
completionHandler(disposition, credential);
}
}
NSURLSessionDataDelegate
收到响应时调用
当NSURLSessionDataTask变为NSURLSessionDownloadTask调用,之后NSURLSessionDataTask将不再接受消息
接受数据过程中,调用,只限于NSURLSessionDataTask
即将缓存响应时调用
后台任务完成成后
NSURLSessionDownloadDelegate
下载中代理
恢复下载代理
下载完成代理