iOS AFNetWorking源码 网络通信模块AFURLSessionManager

640?wx_fmt=jpeg

Linux编程 点击右侧关注,免费入门到精通! 640?wx_fmt=jpeg


作者丨手记/移动互联

https://www.imooc.com/article/284667


作为一个老资历的程序员,优秀的第三方的源码早就开始研究了,但是研究过后就丢在了一边,一直没有整理,最近终于有空了,整理下AFN的源码,加上标注和自己的理解。


  1. AFURLSessionManagerTaskDelegate


 
 

@property (nonatomicweak) AFURLSessionManager *manager;//任务代理的manager A
@property (nonatomicstrongNSMutableData *mutableData;
@property (nonatomicstrongNSProgress *uploadProgress;//上传进度对象
@property (nonatomicstrongNSProgress *downloadProgress;//下载进度对象
@property (nonatomiccopyNSURL *downloadFileURL;//下载文件的URL
@property (nonatomiccopy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomiccopy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomiccopy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomiccopy) 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

2.AFURLSessionManager

初始化AFURLSessionManager,配置manager的属性:session配置、operationQueue发送请求队列、配置session、设置默认通信信息解析策略属性、默认安全策略属性、通信监听属性、属性锁

@property (readwritenonatomicstrongNSURLSessionConfiguration *sessionConfiguration;
@property (readwritenonatomicstrongNSOperationQueue *operationQueue;
@property (readwritenonatomicstrongNSURLSession *session;
@property (readwritenonatomicstrongNSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
@property (readonlynonatomiccopyNSString *taskDescriptionForSessionTasks;
@property (readwritenonatomicstrongNSLock *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

下载中代理

恢复下载代理

下载完成代理


 推荐↓↓↓ 

640?wx_fmt=png

?16个技术公众号】都在这里!

涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。

640?wx_fmt=png万水千山总是情,点个 “ 好看” 行不行
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值