[AFNetworking]二、AFURLSessionManager

AFURLSessionManagerAFNetworking的核心,用于创建和管理NSURLSession,处理NSURLSessionTask等。
初始化AFURLSessionManager

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { self = [super init]; if (!self) { return nil; }if (!configuration) { configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; }self.sessionConfiguration = configuration; self.operationQueue = [[NSOperationQueue alloc] init]; self.operationQueue.maxConcurrentOperationCount = 1; self.responseSerializer = [AFJSONResponseSerializer serializer]; self.securityPolicy = [AFSecurityPolicy defaultPolicy]; #if !TARGET_OS_WATCH self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; #endifself.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init]; self.lock = [[NSLock alloc] init]; self.lock.name = AFURLSessionManagerLockName; __weak typeof(self) weakSelf = self; [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {__strong typeof(weakSelf) strongSelf = weakSelf; for (NSURLSessionDataTask *task in dataTasks) { [strongSelf addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil]; }for (NSURLSessionUploadTask *uploadTask in uploadTasks) { [strongSelf addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil]; }for (NSURLSessionDownloadTask *downloadTask in downloadTasks) { [strongSelf addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil]; } }]; return self; }- (NSURLSession *)session {@synchronized (self) { if (!_session) { _session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; } } return _session; }

*初始化NSURLSessionConfiguration-NSURLSession的配置
*初始化操作队列operationQueue
*初始化responseSerializer,这里默认为json
*初始化securityPolicy,用于处理证书
*初始化session,并将其delegate赋值为self,一个AFURLSessionManager对应一个NSURLSession
通过这个初始化过程,我们可以知道,AFURLSessionManager用于处理证书,管理NSURLSession等。对于session,我们接下来看下是怎样处理的。
管理NSURLSession NSURLSession是一个会话,可以用来创建许多任务NSURLSessionTask,通过这些具体的task可实现Http交互,资源上传下载等。以创建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 {__block NSURLSessionDataTask *dataTask = nil; url_session_manager_create_task_safely(^{ dataTask = [self.session dataTaskWithRequest:request]; }); [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler]; return dataTask; }- (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 { AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask]; delegate.manager = self; delegate.completionHandler = completionHandler; dataTask.taskDescription = self.taskDescriptionForSessionTasks; [self setDelegate:delegate forTask:dataTask]; delegate.uploadProgressBlock = uploadProgressBlock; delegate.downloadProgressBlock = downloadProgressBlock; }

  • 通过[self.session dataTaskWithRequest:request]创建任务
  • 初始化AFURLSessionManagerTaskDelegate,并将delegatetask绑定起来
  • 将任务结束回调completionHandler、上传进度回调uploadProgressBlock、下载进度回调downloadProgressBlock赋值给delegate
NSURLSessionDelegate相关代理 AFURLSessionManager.session中的代理为自己,AFURLSessionManager处理了这些相关回调。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { if (self.sessionDidBecomeInvalid) { self.sessionDidBecomeInvalid(session, error); }[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session]; }

  • session因为某个error或者状态变为invalidate时,回调该函数,在sessionDidBecomeInvalid处理相关逻辑并抛出通知AFURLSessionDidInvalidateNotification
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __block NSURLCredential *credential = nil; if (self.sessionDidReceiveAuthenticationChallenge) { disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential); } else { 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; } } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } }if (completionHandler) { completionHandler(disposition, credential); } }

  • session遇到安全认证challenge时,比如https的证书认证,会回调该函数,通过self.sessionDidReceiveAuthenticationChallenge或者self.securityPolicy来采取对应认证策略。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler { NSURLRequest *redirectRequest = request; if (self.taskWillPerformHTTPRedirection) { redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request); }if (completionHandler) { completionHandler(redirectRequest); } }

  • session遇到重定向时会回调该函数,通过taskWillPerformHTTPRedirection来重定向对应的request
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __block NSURLCredential *credential = nil; if (self.taskDidReceiveAuthenticationChallenge) { disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential); } else { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { disposition = NSURLSessionAuthChallengeUseCredential; credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } }if (completionHandler) { completionHandler(disposition, credential); } }

  • NSURLSessionTask遇到安全认证时,处理逻辑跟session的一样。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler { NSInputStream *inputStream = nil; if (self.taskNeedNewBodyStream) { inputStream = self.taskNeedNewBodyStream(session, task); } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) { inputStream = [task.originalRequest.HTTPBodyStream copy]; }if (completionHandler) { completionHandler(inputStream); } }

  • task需要一个body stream时会回调该函数,用taskNeedNewBodyStream处理这个。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {int64_t totalUnitCount = totalBytesExpectedToSend; if (totalUnitCount == NSURLSessionTransferSizeUnknown) { NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"]; if (contentLength) { totalUnitCount = (int64_t) [contentLength longLongValue]; } }AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; if (delegate) { [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend]; }if (self.taskDidSendBodyData) { self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount); } }

  • task的发送进度,在task对应的AFURLSessionManagerTaskDelegate处理进度并且回调taskDidSendBodyData
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; // delegate may be nil when completing a task in the background if (delegate) { [delegate URLSession:session task:task didCompleteWithError:error]; [self removeDelegateForTask:task]; }if (self.taskDidComplete) { self.taskDidComplete(session, task, error); } }

  • 任务task完成时回调,error为空时则成功,否则任务失败。移除对应的delegate并且回调taskDidComplete
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow; if (self.dataTaskDidReceiveResponse) { disposition = self.dataTaskDidReceiveResponse(session, dataTask, response); }if (completionHandler) { completionHandler(disposition); } }

  • 任务task收到服务器的响应response,并在此决定是否允许NSURLSessionResponseAllow接下来的连接。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; if (delegate) { [self removeDelegateForTask:dataTask]; [self setDelegate:delegate forTask:downloadTask]; }if (self.dataTaskDidBecomeDownloadTask) { self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask); } }

  • 任务task变为下载任务downloadTask
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; [delegate URLSession:session dataTask:dataTask didReceiveData:data]; if (self.dataTaskDidReceiveData) { self.dataTaskDidReceiveData(session, dataTask, data); } }

  • 任务task收到数据data,该函数会多次回调,在delegate处理逻辑并且回调dataTaskDidReceiveData
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { NSCachedURLResponse *cachedResponse = proposedResponse; if (self.dataTaskWillCacheResponse) { cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse); }if (completionHandler) { completionHandler(cachedResponse); } }

  • 任务task即将缓存响应proposedResponse,决定是否允许缓存。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { if (self.didFinishEventsForBackgroundURLSession) { dispatch_async(dispatch_get_main_queue(), ^{ self.didFinishEventsForBackgroundURLSession(session); }); } }

  • 后台session完成。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; 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; } }if (delegate) { [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; } }

  • 下载任务downloadTask完成下载,location为本地临时文件路径。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; if (delegate) { [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; }if (self.downloadTaskDidWriteData) { self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); } }

  • 下载任务downloadTask写入本地数据大小回调,可用于刷新下载进度。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; if (delegate) { [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes]; }if (self.downloadTaskDidResume) { self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes); } }

  • 下载任务downloadTask恢复断点下载,fileOffset为恢复下载偏移位置。
AFURLSessionManagerTaskDelegate AFURLSessionManagerTaskDelegate用于处理进度,接收到的数据等逻辑,一个NSURLSessionTask对应一个代理。
@interface AFURLSessionManagerTaskDelegate : NSObject - (instancetype)initWithTask:(NSURLSessionTask *)task; @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; #if AF_CAN_INCLUDE_SESSION_TASK_METRICS @property (nonatomic, strong) NSURLSessionTaskMetrics *sessionTaskMetrics; #endif @property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; @property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock; @property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock; @property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler; @end

  • mutableData为接收到的数据
  • uploadProgress代表上传进度,uploadProgressBlock为上传进度回调
  • downloadProgress代表下载进度,downloadProgressBlock为下载进度回调
  • completionHandler为任务完成时的回调。
初始化
- (instancetype)initWithTask:(NSURLSessionTask *)task { self = [super init]; if (!self) { return nil; }_mutableData = https://www.it610.com/article/[NSMutableData data]; _uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; _downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; __weak __typeof__(task) weakTask = task; for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]) { progress.totalUnitCount = NSURLSessionTransferSizeUnknown; progress.cancellable = YES; progress.cancellationHandler = ^{ [weakTask cancel]; }; progress.pausable = YES; progress.pausingHandler = ^{ [weakTask suspend]; }; if ([progress respondsToSelector:@selector(setResumingHandler:)]) { progress.resumingHandler = ^{ [weakTask resume]; }; }[progress addObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) options:NSKeyValueObservingOptionNew context:NULL]; } return self; }

  • 初始化_mutableData_uploadProgress_downloadProgress
  • KVO监听上传进度和下载进度属性fractionCompleted
进度回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([object isEqual:self.downloadProgress]) { if (self.downloadProgressBlock) { self.downloadProgressBlock(object); } } else if ([object isEqual:self.uploadProgress]) { if (self.uploadProgressBlock) { self.uploadProgressBlock(object); } } }

  • 这里使用KVO的回调,再回调对应的上传或下载进度block
代理相关
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { __strong AFURLSessionManager *manager = self.manager; __block id responseObject = nil; __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; userInfo[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.sessionTaskMetrics) { userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics; }if (self.downloadFileURL) { userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL; } else if (data) { userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data; }if (error) { userInfo[AFNetworkingTaskDidCompleteErrorKey] = error; 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]; }); }); }); } }

  • 这里处理任务完成时的回调,将接收到的数据、文件路径等封装到userInfo中,回调completionHandler并抛出通知AFNetworkingTaskDidCompleteNotification
- (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive; self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived; [self.mutableData appendData:data]; }

  • 处理接收到的数据,并且更新下载进度
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend; self.uploadProgress.completedUnitCount = task.countOfBytesSent; }

  • 更新上传进度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite; self.downloadProgress.completedUnitCount = totalBytesWritten; }- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{self.downloadProgress.totalUnitCount = expectedTotalBytes; self.downloadProgress.completedUnitCount = fileOffset; }

  • 更新下载进度
【[AFNetworking]二、AFURLSessionManager】AFNetworking相关文章:
[AFNetworking]一、简介
[AFNetworking]二、AFURLSessionManager
[AFNetworking]三、AFHTTPSessionManager
[AFNetworking]四、AFURLRequestSerialization
[AFNetworking]五、AFURLResponseSerialization

    推荐阅读