开源库信息
AFNetWorking 源码解析 AFNetWorking 组成 AFNetWorking 主要由如下图几个部分构成
AFURLSessionManager 是整个开源库的核心,它连接着AFNetWorking其他几个重要部分,它是AFHTTPSessionManager的父类,一般我们在使用的时候一般使用AFHTTPSessionManager。但是核心部分还是集中在AFURLSessionManager中。AFURLSessionManager遵循了NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate一大堆的协议,并将AFHTTPSessionManager作为URLSession 的 delegate。这样在URLSession 触发一系列关键事件的时候,够可以交给AFURLSessionManager接管处理。
AFHTTPRequestSerializer
AFHTTPResponseSerializer
AFHTTPRequestSerializer,AFHTTPResponseSerializer 分别是请求序列化器和返回体序列化器,引入序列化器后,序列化器就相当于一个插件一样,这样做的好处不言而喻,增加了整个系统的灵活性,比如我们应用中可能会对接不同的后端,这些后端可能有着不同的数据交付格式,有了序列化器后就可以针对不同的后端数据交付格式实现一对序列化器。整个框架就显得十分灵活,AFNetworking 也根据常见的需求实现了一些常用的序列化器,例如 AFJSONRequestSerializer,AFPropertyListRequestSerializer这两类请求序列化器;AFJSONResponseSerializer,AFXMLParserResponseSerializer,AFXMLDocumentResponseSerializer, AFPropertyListResponseSerializer,AFImageResponseSerializer,AFCompoundResponseSerializer 这几类返回体序列化器。
AFNetworkReachabilityManager
AFNetworkReachabilityManager 主要用于检测网络可用性,这对于应用来说也是非常常用的一项功能。
AFSecurityPolicy 主要用于提供安全认证相关的处理,
AFNetWorking 框架总览 下面是AFNetWorking 整个框架重要流程的大致结构图,下面将针对这张图对源码进行进一步解析:
上面提到AFURLSessionManager是整个AFNetWorking的核心部分,在iOS中我们如果需要执行网络请求需要URLSession,AFNetWorking也一样,它只不过是对URLSession的一个封装,最核心的部分还是借助URLSession来完成,因此我们最先要弄清楚AFURLSessionManager是如何串起来的,我们上面提到了AFURLSessionManager实现了一系列的协议,并作为URLSession的delegate。这样我们在使用URLSession进行网络请求的时候就会触发delegate的对应方法进行处理,从而将流程交接给AFURLSessionManager。然后再由AFURLSessionManager调用其他的部件对数据进行后续处理。我们来看下AFURLSessionManager的初始化代码,看下AFURLSessionManager是由哪些部分组成:
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration * )configuration { if (! configuration) { configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; } self .sessionConfiguration = configuration; self .operationQueue = [[NSOperationQueue alloc] init ]; self .operationQueue.maxConcurrentOperationCount = 1 ; self .session = [NSURLSession sessionWithConfiguration:self .sessionConfiguration delegate:self delegateQueue:self .operationQueue]; self .responseSerializer = [AFJSONResponseSerializer serializer]; self .securityPolicy = [AFSecurityPolicy defaultPolicy]; self .reachabilityManager = [AFNetworkReachabilityManager sharedManager]; self .mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init ]; return self ; }
在初始化方法中,主要初始化了self.session,self.responseSerializer,self.securityPolicy,self.reachabilityManager 这些对象,并给self.session指定了delegate,delegate执行的队列,以及配置。
介绍了AFURLSessionManager接下来就按照应用场景对AFNetWorking进行介绍:
这部分我们会以常见的GET请求为例子来过下整个流程:
- (NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(id )parameters progress:(void (^)(NSProgress * _Nonnull))downloadProgress success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure { NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:downloadProgress success:success failure:failure]; [dataTask resume]; return dataTask; }
在GET中主要通过dataTaskWithHTTPMethod创建了一个NSURLSessionDataTask对象,然后通过resume执行这个task。
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id )parameters uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress success:(void (^)(NSURLSessionDataTask *, id ))success failure:(void (^)(NSURLSessionDataTask *, NSError *))failure { NSError *serializationError = nil ; NSMutableURLRequest *request = [self .requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self .baseURL] absoluteString] parameters:parameters error:&serializationError]; if (serializationError) { if (failure) { dispatch_async (self .completionQueue ?: dispatch_get_main_queue(), ^{ failure(nil , serializationError); }); } return nil ; } __block NSURLSessionDataTask *dataTask = nil ; dataTask = [self dataTaskWithRequest:request uploadProgress:uploadProgress downloadProgress:downloadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { if (error) { if (failure) { failure(dataTask, error); } } else { if (success) { success(dataTask, responseObject); } } }]; return dataTask; }
dataTaskWithHTTPMethod 方法中主要分成两大部分:
1. 构建NSMutableURLRequest2. 构建NSURLSessionDataTask
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id )parameters error:(NSError *__autoreleasing *)error { NSURL *url = [NSURL URLWithString:URLString]; NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url]; mutableRequest.HTTPMethod = method; for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { if ([self .mutableObservedChangedKeyPaths containsObject:keyPath]) { [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath]; } } mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy]; return mutableRequest; }
NSMutableURLRequest 主要由NSURL,HTTPMethod,HTTPBody,allHTTPHeaderFields,parameters 以及一些配置属性构成。这里有个比较关键的点,如何将对当前属性的设置同步到mutableRequest中。这里用的是KVO来实现,下面这部分的关键代码:
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) { [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath]; } }
首先会遍历AFHTTPRequestSerializerObservedKeyPaths,如果有在mutableObservedChangedKeyPaths中,mutableRequest就对这个属性进行监听。下面是AFHTTPRequestSerializerObservedKeyPaths的定义:
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() { static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil ; static dispatch_once_t onceToken; dispatch_once (&onceToken, ^{ _AFHTTPRequestSerializerObservedKeyPaths = @[ NSStringFromSelector (@selector (allowsCellularAccess)), NSStringFromSelector (@selector (cachePolicy)), NSStringFromSelector (@selector (HTTPShouldHandleCookies)), NSStringFromSelector (@selector (HTTPShouldUsePipelining)), NSStringFromSelector (@selector (networkServiceType)), NSStringFromSelector (@selector (timeoutInterval)) ]; }); return _AFHTTPRequestSerializerObservedKeyPaths; }
那么mutableObservedChangedKeyPaths是怎么来的?这部分在AFHTTPRequestSerializer请求序列化器的初始化方法中有做处理,我们看下这部分代码:
- (instancetype)init { self .stringEncoding = NSUTF8StringEncoding ; self .mutableHTTPRequestHeaders = [NSMutableDictionary dictionary]; self .requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue" , DISPATCH_QUEUE_CONCURRENT ); NSMutableArray * acceptLanguagesComponents = [NSMutableArray array]; [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL * stop) { float q = 1 .0f - (idx * 0 .1f); [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g" , obj, q]]; * stop = q <= 0 .5f; }]; [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", " ] forHTTPHeaderField:@"Accept-Language" ]; NSString * userAgent = nil ; userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)" , [[NSBundle mainBundle] infoDictionary][(__bridge NSString * )kCFBundleExecutableKey] ? : [[NSBundle mainBundle] infoDictionary][(__bridge NSString * )kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString" ] ? : [[NSBundle mainBundle] infoDictionary][(__bridge NSString * )kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]]; if (userAgent) { if (! [userAgent canBeConvertedToEncoding:NSASCIIStringEncoding ]) { NSMutableString * mutableUserAgent = [userAgent mutableCopy]; if (CFStringTransform ((__bridge CFMutableStringRef )(mutableUserAgent), NULL , (__bridge CFStringRef )@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove" , false )) { userAgent = mutableUserAgent; } } [self setValue:userAgent forHTTPHeaderField:@"User-Agent" ]; } self .HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET" , @"HEAD" , @"DELETE" , nil ]; self .mutableObservedChangedKeyPaths = [NSMutableSet set ]; for (NSString * keyPath in AFHTTPRequestSerializerObservedKeyPaths ()) { if ([self respondsToSelector:NSSelectorFromString (keyPath)]) { [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext ]; } } return self ; }
这里主要对请求的字符串编码格式,请求头进行设置,以及通过keyPath方式往mutableObservedChangedKeyPaths中添加要监听的keyPath。KVO 方式监听的方式是NSKeyValueObservingOptionNew,也就是这些被监听的属性新建的时候就会被通知,我们接下来看下收到通知后的处理:
- (void )observeValueForKeyPath:(NSString *)keyPath ofObject:(__unused id )object change:(NSDictionary *)change context:(void *)context { if (context == AFHTTPRequestSerializerObserverContext) { if ([change[NSKeyValueChangeNewKey ] isEqual:[NSNull null]]) { [self .mutableObservedChangedKeyPaths removeObject:keyPath]; } else { [self .mutableObservedChangedKeyPaths addObject:keyPath]; } } }
看到这里大家就可以明白了mutableObservedChangedKeyPaths是怎么来的:一旦我们监听的属性被创建后,就会跑到observeValueForKeyPath中,在observeValueForKeyPath方法中,会根据该属性是否为nil来决定是从mutableObservedChangedKeyPaths删除还是添加到mutableObservedChangedKeyPaths中。
我们这里对这部分做个总结: 在AFHTTPRequestSerializer请求序列化器初始化过程中会对AFHTTPRequestSerializerObservedKeyPaths中指定的属性通过KVO进行监听,监听这些对象的新建事件,一旦新建就会添加到mutableObservedChangedKeyPaths,然后每次发起请求前构造NSMutableRequest的时候,对存在于mutableObservedChangedKeyPaths中的属性进行KVO监听。这样一旦我们设置了序列化器中的对应属性,这些属性的状态就会同步到NSMutableRequest中。
我们接下来再回到请求的构建过程中:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id )parameters error:(NSError *__autoreleasing *)error { NSParameterAssert (request); NSMutableURLRequest *mutableRequest = [request mutableCopy]; [self .HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }]; NSString *query = nil ; if (parameters) { if (self .queryStringSerialization) { NSError *serializationError; query = self .queryStringSerialization(request, parameters, &serializationError); if (serializationError) { if (error) { *error = serializationError; } return nil ; } } else { switch (self .queryStringSerializationStyle) { case AFHTTPRequestQueryStringDefaultStyle: query = AFQueryStringFromParameters(parameters); break ; } } } if ([self .HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { if (query && query.length > 0 ) { mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@" , query]]; } } else { if (!query) { query = @"" ; } if (![mutableRequest valueForHTTPHeaderField:@"Content-Type" ]) { [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type" ]; } [mutableRequest setHTTPBody:[query dataUsingEncoding:self .stringEncoding]]; } return mutableRequest; }
在这部分中我们会将初始化序列化器方法中指定的UA Accept-Language 这些头信息放置到请求中。 接着根据queryStringSerialization来决定需要对parameters进行序列化处理还是转换成“key1 = value1 & key2 = value2的形式 ”形式。再根据self.HTTPMethodsEncodingParametersInURI决定是将参数放到url上还是body中。到此为止请求对象构建完毕。
- (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; }
NSURLSessionDataTask的创建是通过URLSession创建并管理的,要创建NSURLSessionDataTask需要将上个步骤创建的NSMutableRequest传给URLSession通过dataTaskWithRequest方法返回NSURLSessionDataTask实例,然后再通过addDelegateForDataTask,往task中添加 uploadProgressBlock,downloadProgressBlock,completionHandler 这些都是AFNetWorking向外面传递数据的接口,我们接下来看下addDelegateForDataTask :
- (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; }
在这个方法中会创建一个AFURLSessionManagerTaskDelegate,每个NSURLSessionDataTask都会与一个AFURLSessionManagerTaskDelegate相关联,这是通过****[self setDelegate:delegate forTask:dataTask]****来完成的,在setDelegate方法中将taskidentify 作为key delegate为value 存到 mutableTaskDelegatesKeyedByTaskIdentifier字典中。 AFURLSessionManagerTaskDelegate主要负责两个任务,一个是负责进度的更新,一个是的网络数据mutableData的管理。这个会在后面进行介绍。每个AFURLSessionManagerTaskDelegate持有uploadProgressBlock,downloadProgressBlock,completionHandler以及AFURLSessionManager,在进度发生变化的时候都会通过uploadProgressBlock,downloadProgressBlock传出,当网络数据结束后,通过completionHandler传出。
那么AFURLSessionManagerTaskDelegate又是怎么和AFURLSessionManager产生关联的? 我们上面提到,所有的事件源于URLSession的各个代理,而通过将AFURLSessionManager设置为URLSession从而将事件传递到AFURLSessionManager,那么怎么将这些事件传给AFURLSessionManagerTaskDelegate呢?
- (void )URLSession:(NSURLSession *)session task :(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task ]; if (delegate) { [delegate URLSession:session task :task didCompleteWithError:error]; [self removeDelegateForTask:task ]; } if (self.taskDidComplete) { self.taskDidComplete(session, task , error); } }
这就涉及到上面提到的mutableTaskDelegatesKeyedByTaskIdentifier,我们每个dataTask被新建的时候,都会同时新建一个AFURLSessionManagerTaskDelegate,并添加到mutableTaskDelegatesKeyedByTaskIdentifier,建立起以taskidentify为key AFURLSessionManagerTaskDelegate为value的映射关系。我们看上面的代理方法,会将task作为参数传进来,来表示具体是哪个task的回调,这时候通过task就可以找到对应的AFURLSessionManagerTaskDelegate 对象,并调用对应的方法进行处理,这就完成了AFURLSessionManager向AFURLSessionManagerTaskDelegate关联的环节。
在介绍这部分之前我们先来看下NSURLSessionDataDelegate
#pragma mark - NSURLSessionDataDelegate - (void )URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{ completionHandler(NSURLSessionResponseAllow ); } - (void )URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { [self .receiveData appendData:data]; } - (void )URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ if (error){ NSLog (@"error = %@\n" ,error); } else { NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:self .receiveData options:NSJSONReadingMutableContainers | NSJSONReadingAllowFragments error:nil ]; NSLog (@"response content = %@" ,dic); } }
在收到数据的时候会首先调用URLSession:dataTask:didReceiveResponse:completionHandler 这个代理方法,可以在这个方法中根据返回的response来决定该任务是继续执行,还是转化为其他类型的任务。然后在 URLSession:dataTask:didReceiveData 中接送回传的数据,最后走 URLSession: task: didCompleteWithError 对数据进行交付。
我们紧接着就来看下AFNetWorking中是如何处理这部分流程的:
URLSession:dataTask:didReceiveResponse:completionHandler 方法中,AFURLSessionManager会通过block介入整个流程来决定到底是继续执行还是转换为其他类型任务。
- (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); } }
在接到数据后先通过delegateForTask方法拿到当前task对应的AFURLSessionManagerTaskDelegate,然后交给它进行处理。
- (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); } }
在NSURLSessionDataDelegate 中将该次到达的数据通过appendData添加到self.mutableData,到数据接收完毕后就会将self.mutableData交付出去。
- (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]; }
等到数据接收结束后会回调URLSession: task: didCompleteWithError 这里同样会将流程转到task对应的AFURLSessionManagerTaskDelegate进行处理,最后将task从字典中移除。
- (void )URLSession:(NSURLSession *)session task :(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task ]; if (delegate) { [delegate URLSession:session task :task didCompleteWithError:error]; [self removeDelegateForTask:task ]; } if (self.taskDidComplete) { self.taskDidComplete(session, task , error); } }
在AFURLSessionManagerTaskDelegate中会将数据传递给responseSerializer,对数据进行预先处理后,通过bock以及通知将数据交付给应用层。
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 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]; }); }); }); } }
我们看下返回体序列化器的处理过程,这里以最常用的AFJSONResponseSerializer 来进行分析:
- (id )responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error { if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData , AFURLResponseSerializationErrorDomain)) { return nil ; } } NSError *serializationError = nil ; id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self .readingOptions error:&serializationError]; return responseObject; }
responseObjectForResponse 方法就完成两件事情:
1. 对返回response数据进行合法性校验2. 对NSData 进行对应处理后(序列化)后返回
在validateResponse 中主要完成contentType 以及 statusCode校验。
- (BOOL )validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error { BOOL responseIsValid = YES ; NSError *validationError = nil ; if (response && [response isKindOfClass:[NSHTTPURLResponse class ]]) { if (self .acceptableContentTypes && ![self .acceptableContentTypes containsObject:[response MIMEType]] && !([response MIMEType] == nil && [data length] == 0 )) { if ([data length] > 0 && [response URL]) { } responseIsValid = NO ; } if (self .acceptableStatusCodes && ![self .acceptableStatusCodes containsIndex:(NSUInteger )response.statusCode] && [response URL]) { responseIsValid = NO ; } } if (error && !responseIsValid) { *error = validationError; } return responseIsValid; }
在上传数据或者下载数据的时候会分别回调didSendBodyData,didWriteData进行处理,在这两个代理回调中都会将数据传递到AFURLSessionManagerTaskDelegate中。
- (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); } }
- (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); } }
在AFURLSessionManagerTaskDelegate中分别更新self.uploadProgress以及self.downloadProgress
- (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; }
但是我们并没看到进度数据的交付啊,这部分其实是在初始化AFURLSessionManagerTaskDelegate的时候利用KVO将进度数据与对应的Block的调用进行了关联:
- (instancetype )initWithTask:(NSURLSessionTask *)task { _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 addObserver:self forKeyPath:NSStringFromSelector (@selector (fractionCompleted)) options:NSKeyValueObservingOptionNew context:NULL ]; } return self ; }
在initWithTask中利用KVO监听progress 的 fractionCompleted。一旦有数据变动,都会触发KVO:
- (void )observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)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 ); } } }
在observeValueForKeyPath中调用对应的downloadProgressBlock以及uploadProgressBlock 进行数据交付。 扯个不是非常必要的一个问题:为什么需要AFURLSessionManagerTaskDelegate ,AFURLSessionManagerTaskDelegate 的职责是什么?直接说答案吧:AFURLSessionManagerTaskDelegate 主要处理与task相关的代理,因为不同的task有不同的进度,不同task完成数据接收的时刻也不同,AFURLSessionManagerTaskDelegate就是用来与task相关的代理。
这部分主要在调用默认的resume以及suspend方法的时候增加AFNSURLSessionTaskDidResumeNotification , AFNSURLSessionTaskDidSuspendNotification 的通知,实现方式是通过在load方法中替换resume以及suspand的实现,为自己的af_resume以及af_suspend,在这里添加对应的通知。那么为什么要添加这两个通知?我们在介绍任务创建的时候会调用setDelegate:forTask方法。在这里会调用****[self addNotificationObserverForTask:task]****
- (void )setDelegate:(AFURLSessionManagerTaskDelegate *)delegate forTask:(NSURLSessionTask *)task { [self.lock lock ]; self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate ; [self addNotificationObserverForTask:task ]; [self.lock unlock ]; }
在addNotificationObserverForTask方法中会让NSURLSessionTask监听AFNSURLSessionTaskDidResumeNotification ,以及AFNSURLSessionTaskDidSuspendNotification
- (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 )taskDidResume:(NSNotification *)notification { NSURLSessionTask *task = notification.object; if ([task respondsToSelector:@selector (taskDescription)]) { if ([task.taskDescription isEqualToString:self .taskDescriptionForSessionTasks]) { dispatch_async (dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task]; }); } } } - (void )taskDidSuspend:(NSNotification *)notification { NSURLSessionTask *task = notification.object; if ([task respondsToSelector:@selector (taskDescription)]) { if ([task.taskDescription isEqualToString:self .taskDescriptionForSessionTasks]) { dispatch_async (dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task]; }); } } }
通过 AFSecurityPolicy 保证请求安全
AFSecurityPolicy AFSecurityPolicy 作为 AFURLSessionManager一个主要的组件,主要用于验证 HTTPS 请求的证书是否有效。它有三种模式:
typedef NS_ENUM (NSUInteger , AFSSLPinningMode ) { AFSSLPinningModeNone , AFSSLPinningModePublicKey , AFSSLPinningModeCertificate , };
* AFSSLPinningModeNone 不使用**** pinned certificates**** 进行认证,只会在系统的信任的证书列表中对服务端返回的证书进行验证* AFSSLPinningModeCertificate 需要客户端保存服务端的证书* AFSSLPinningModePublicKey 也需要预先保存服务端发送的证书,但是这里只会验证证书中的公钥是否正确
我们先来看下在AFURLSessionManager中什么时机使用AFSecurityPolicy,在发起某个请求的时候如果需要认证的时候会回调NSURLSession中的didReceiveChallenge方法,同样这里也会将该处理转发给AFURLSessionManager,下面是AFURLSessionManager对didReceiveChallenge的处理:
- (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); } }
所以整个环节中最重要的就是evaluateServerTrust方法了,在看这个方法之前我们先看下AFSecurityPolicy是怎么初始化的:
如果我们没有人为指定证书文件,AFNetWorking 会使用defaultPolicy
+ (instancetype )defaultPolicy { AFSecurityPolicy *securityPolicy = [[self alloc] init]; securityPolicy.SSLPinningMode = AFSSLPinningModeNone ; return securityPolicy; }
defaultPolicy实现十分简单,就是创建了一个AFSecurityPolicy对象后指定对应的SSLPinningMode为AFSSLPinningModeNone。
紧接着我们看下evaluateServerTrust这个方法,关键的地方已经加了注释,大家可以对照注释进行理解,这里就不再展开介绍了:
- (BOOL )evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain { if (domain && self .allowInvalidCertificates && self .validatesDomainName && (self .SSLPinningMode == AFSSLPinningModeNone || [self .pinnedCertificates count] == 0 )) { NSLog (@"In order to validate a domain name for self signed certificates, you MUST use pinning." ); return NO ; } NSMutableArray *policies = [NSMutableArray array]; if (self .validatesDomainName) { [policies addObject:(__bridge_transfer id )SecPolicyCreateSSL(true , (__bridge CFStringRef )domain)]; } else { [policies addObject:(__bridge_transfer id )SecPolicyCreateBasicX509()]; } SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef )policies); if (self .SSLPinningMode == AFSSLPinningModeNone) { return self .allowInvalidCertificates || AFServerTrustIsValid(serverTrust); } else if (!AFServerTrustIsValid(serverTrust) && !self .allowInvalidCertificates) { return NO ; } switch (self .SSLPinningMode) { case AFSSLPinningModeNone: default : return NO ; case AFSSLPinningModeCertificate: { NSMutableArray *pinnedCertificates = [NSMutableArray array]; for (NSData *certificateData in self .pinnedCertificates) { [pinnedCertificates addObject:(__bridge_transfer id )SecCertificateCreateWithData(NULL , (__bridge CFDataRef )certificateData)]; } SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef )pinnedCertificates); if (!AFServerTrustIsValid(serverTrust)) { return NO ; } NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) { if ([self .pinnedCertificates containsObject:trustChainCertificate]) { return YES ; } } return NO ; } case AFSSLPinningModePublicKey: { NSUInteger trustedPublicKeyCount = 0 ; NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust); for (id trustChainPublicKey in publicKeys) { for (id pinnedPublicKey in self .pinnedPublicKeys) { if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) { trustedPublicKeyCount += 1 ; } } } return trustedPublicKeyCount > 0 ; } } return NO ; }
那如果我们需要添加证书文件要怎么实现呢?下面是一个例子供大家参考
- (void )setSecurityPolicyWithCerPath:(NSString *)cerPath validatesDomainName:(BOOL )validatesDomainName { NSData *cerData = [NSData dataWithContentsOfFile:cerPath]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; securityPolicy.allowInvalidCertificates = YES ; securityPolicy.validatesDomainName = validatesDomainName; securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:cerData, nil ]; [self setSecurityPolicy:securityPolicy]; }
通过AFNetworkReachabilityManager 监控网络状态
一般我们应用都会有个应用场景:在网络断开或者异常的时候,显示重试页面,当网络恢复的时候自动调用数据获取接口,恢复正常界面。这个功能就可以通过AFNetworkReachabilityManager来实现了。
AFNetworkReachabilityManager实例的创建:
+ (instancetype )sharedManager { static AFNetworkReachabilityManager *_sharedManager = nil ; static dispatch_once_t onceToken; dispatch_once (&onceToken, ^{ _sharedManager = [self manager]; }); return _sharedManager; }
不解释,嗯!
- (void )startMonitoring { [self stopMonitoring]; if (!self .networkReachability) { return ; } __weak __typeof (self )weakSelf = self ; AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof (weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } }; SCNetworkReachabilityContext context = {0 , (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL }; SCNetworkReachabilitySetCallback (self .networkReachability, AFNetworkReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop (self .networkReachability, CFRunLoopGetMain (), kCFRunLoopCommonModes); dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ),^{ SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags (self .networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } }); }
通过上述设置后,每次网络状态改变就会调用 AFNetworkReachabilityCallback 函数,在这里会调用AFPostReachabilityStatusChange抛出状态改变的通知:
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target , SCNetworkReachabilityFlags flags , void * info ) { AFPostReachabilityStatusChange(flags , (__bridge AFNetworkReachabilityStatusBlock) info); }
我们知道状态抛出是通过开启监听之前设置的AFNetworkReachabilityStatusBlock 类型的callback block 传递到业务层的。
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags , AFNetworkReachabilityStatusBlock block ) { AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags ); dispatch_async(dispatch_get_main_queue(), ^{ if (block ) { block (status); } NSNotificationCenter *notificationCenter = [NSNotificationCenter default Center]; NSDictionary *user Info = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) }; [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil user Info:user Info]; }); }
AFPostReachabilityStatusChange会先通过AFNetworkReachabilityStatusForFlags从SCNetworkReachabilityFlags中提取对应的标志生成AFNetworkReachabilityStatus对象,在使用AFNetworkReachabilityStatusBlock传递出去,同时通过AFNetworkingReachabilityDidChangeNotification广播通知其他部件。
上述的flag是一个kSCNetworkReachabilityFlagsReachable类型,不同的位代表不同的状态。
static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0 ); BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0 ); BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0 ) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0 )); BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0 ); BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; if (isNetworkReachable == NO) { status = AFNetworkReachabilityStatusNotReachable; } else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0 ) { status = AFNetworkReachabilityStatusReachableViaWWAN; } else { status = AFNetworkReachabilityStatusReachableViaWiFi; } return status; }
好了好了,说好不熬夜的又2点了,不早了就这样吧。……(^_^)v