继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

iOS AFNetWorking源码 网络通信模块AFURLSessionManager

ZKReadStone
关注TA
已关注
手记 52
粉丝 32
获赞 322

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

  1. 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
  1. 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
下载中代理
恢复下载代理
下载完成代理
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP