通讀AFN①--從創(chuàng)建manager到數(shù)據(jù)解析完畢

原文來自:http://www.cnblogs.com/Mike-zh/p/5167017.html

流程梳理

今天開始會(huì)寫幾篇關(guān)于AFN源碼解讀的一些Blog,首先要梳理一下AFN的整體結(jié)構(gòu)(主要是討論2.x版本的Session訪問模塊):我們先看看我們最常用的一段代碼:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];[manager GET:@"https://www.baidu.com"parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id? _Nullable responseObject) {// ... successHandler} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// ... failureHandler}];

在前面關(guān)于AFN URLEncode 的文章說道,AFN將網(wǎng)絡(luò)訪問分為三個(gè)過程化的模塊,下面我把第一部分再分為兩個(gè)步驟:

1.訪問前的準(zhǔn)備:使用AFURLRequestSerialization類創(chuàng)建一個(gè)新的URLRequest對象(用于即將進(jìn)行的網(wǎng)絡(luò)訪問),對傳遞過來的URLrequest對象進(jìn)行三步加工:

①配置默認(rèn)網(wǎng)絡(luò)配置,如(allowsCellularAccess,cachePolicy,HTTPShouldHandleCookies,HTTPShouldUsePipelining,networkServiceType,timeoutInterval)

②將request的HTTPHeader賦給新的request

③將parameter字典轉(zhuǎn)為queryString,拼接在URLRequest的URL后面.如果是POST,PUT,PATCH方法,則放在HTTPBody中,并設(shè)置Content-Type頭為表單類型:application/x-www-form-urlencoded

2.用1中所得的mutableRequest對象創(chuàng)建dataTask

3.訪問過程中,將代理職責(zé)下放給AFURLSessionManagerTaskDelegate,通過代理方法接收數(shù)據(jù)。

4.完全接受到數(shù)據(jù)或失敗之后的處理:失敗回調(diào)、成功后解析然后回調(diào)。

上面四個(gè)步驟都是在[manager GET: parameters: success: failure:]這個(gè)方法中完成的,而在進(jìn)行網(wǎng)絡(luò)訪問之前的[AFHTTPSessionManager manager]是對網(wǎng)絡(luò)訪問過程組件的初始化,也就是,在AFHTTPSessionManager的+manager方法中,完成了對自己和requestSerializer以及responseSerializer的初始化工作,+manager方法內(nèi)部的代碼:

self.baseURL = url;self.requestSerializer = [AFHTTPRequestSerializerserializer];self.responseSerializer = [AFJSONResponseSerializerserializer];

可以看出requestSerializer和responseSerializer對象都是按照默認(rèn)的構(gòu)造方法serializer創(chuàng)建的,同時(shí)可以看出responseSerializer默認(rèn)使用了JSON的解析方式,著也是為什么當(dāng)使用AFN進(jìn)行網(wǎng)絡(luò)請求時(shí),JSON會(huì)自動(dòng)進(jìn)行解析的原因。看到這里我們也了解了如果想進(jìn)行修改默認(rèn)的request和response序列化方式修改,在何時(shí)添加這部分代碼。就是在manager的默認(rèn)設(shè)置完成之后,在開始進(jìn)行網(wǎng)絡(luò)訪問三步走之前:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];manager.requestSerializer = [AFJSONRequestSerializer serializer];manager.responseSerializer = [AFXMLParserResponseSerializer serializer];[manager GET:@"https://www.baidu.com"parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id? _Nullable responseObject) {// ... successHandler} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// ... failureHandler}];

我們能改變的不僅僅是request和reponse按照什么格式序列化,還可以改變默認(rèn)的session配置,進(jìn)行創(chuàng)建Task的session對象在AFN中成為了AFHTTPSessionManager的屬性,如果不使用構(gòu)造方法- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration傳給它一個(gè)值,它會(huì)在AFHTTPSessionManager的父類AFURLRequestSerialization中默認(rèn)配置的,不光如此,而且還配置了AFHTTPSessionManager的很多重要屬性,在AFURLRequestSerialization的-initWithBaseURL: sessionConfiguration:中:

if(!configuration) {? ? configuration = [NSURLSessionConfigurationdefaultSessionConfiguration];}self.sessionConfiguration = configuration;self.operationQueue = [[NSOperationQueuealloc] init];self.operationQueue.maxConcurrentOperationCount =1;self.session = [NSURLSessionsessionWithConfiguration:self.sessionConfigurationdelegate:selfdelegateQueue:self.operationQueue];self.responseSerializer = [AFJSONResponseSerializerserializer];self.securityPolicy = [AFSecurityPolicydefaultPolicy];self.reachabilityManager = [AFNetworkReachabilityManagersharedManager];self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionaryalloc] init];self.lock = [[NSLockalloc] init];self.lock.name =AFURLSessionManagerLockName;[self.sessiongetTasksWithCompletionHandler:^(NSArray*dataTasks,NSArray*uploadTasks,NSArray*downloadTasks) {for(NSURLSessionDataTask*taskindataTasks) {? ? ? ? [selfaddDelegateForDataTask:taskcompletionHandler:nil];? ? }for(NSURLSessionUploadTask*uploadTaskinuploadTasks) {? ? ? ? [selfaddDelegateForUploadTask:uploadTaskprogress:nilcompletionHandler:nil];? ? }for(NSURLSessionDownloadTask*downloadTaskindownloadTasks) {? ? ? ? [selfaddDelegateForDownloadTask:downloadTaskprogress:nildestination:nilcompletionHandler:nil];? ? }}];[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(taskDidResume:)name:AFNSURLSessionTaskDidResumeNotificationobject:nil];[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(taskDidSuspend:)name:AFNSURLSessionTaskDidSuspendNotificationobject:nil];returnself;

這些默認(rèn)的配置大多是不可以在外部修改,因?yàn)榇蠖紴閞eadonly屬性,只是在實(shí)現(xiàn)文件中給了修改的接口。例如:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];// 設(shè)置最大并發(fā)操作數(shù)manager.operationQueue.maxConcurrentOperationCount =3;// error[manager GET: parameter: success: failure:];

AFN網(wǎng)絡(luò)訪問的默認(rèn)設(shè)置大多都是不希望用戶修改的,對外提供的接口也僅僅局限于request和response的序列化方式的修改。看完了這些,我們來著重看一下網(wǎng)絡(luò)訪問三步走的過程:

1.訪問前的準(zhǔn)備:使用AFURLRequestSerialization類創(chuàng)建一個(gè)新的URLRequest對象

這一部分的很多知識(shí)點(diǎn),在這篇文章iOS. PercentEscape是錯(cuò)用的URLEncode,看看AFN和Facebook吧中有介紹,這里說一些補(bǔ)充的內(nèi)容:

首先是requestSerializer的創(chuàng)建細(xì)節(jié):這個(gè)雖然不屬于這部分內(nèi)容(它是在+manager方法中就創(chuàng)建了),但有些問題還需注意:

這個(gè)創(chuàng)建過程主要是設(shè)置默認(rèn)編碼為UTF8,對Accept-Language、User-Agent兩個(gè)頭的初始化,設(shè)置允許queryString放在URL中的HTTP請求方法為@"GET", @"HEAD", @"DELETE"、添加對@[@"allowsCellularAccess", @"cachePolicy", @"HTTPShouldHandleCookies", @"HTTPShouldUsePipelining", @"networkServiceType", @"timeoutInterval"]屬性值(這些key通過一個(gè)靜態(tài)數(shù)組獲得)的觀察者為本身。

需要注意的是請求頭本來是Request的屬性,這里設(shè)置請求頭是用requestSerilizer對象的一個(gè)字典屬性mutableHTTPRequestHeaders將它們先存儲(chǔ)起來,以備在修改傳遞過來的request對象過程中使用。

為什么要KVO以上6個(gè)屬性?

字典屬性mutableObservedChangedKeyPaths用來存儲(chǔ)這6個(gè)屬性值中非空的值,如果這6個(gè)屬性中的任何一個(gè)被賦了新值,就會(huì)在observeValueForKeyPath:中檢查新值是否為空,如果為空,就從mutableObservedChangedKeyPaths中移出這個(gè)對象,表示不再需要考慮這個(gè)值對配置的影響。而這些非空的值會(huì)在進(jìn)行網(wǎng)絡(luò)訪問前創(chuàng)建新的mutableRequest對象的時(shí)候一一賦給它(這些屬性本來就是URLRequest對象的屬性)。

這個(gè)過程我們可以換一個(gè)思路實(shí)現(xiàn),就是非空給屬性賦值,空時(shí)賦給屬性NSNull,在將這些屬性賦給mutableRequest的時(shí)候判斷是否為NSNull,如果是,就不賦值了。相比之下AFN的做法對擴(kuò)展性更好一些。而這種方法的使用在AFN是非常常見的。

下面我們就看一下mutableRequest創(chuàng)建的細(xì)節(jié)吧:

- (NSMutableURLRequest*)requestWithMethod:(NSString*)method? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? URLString:(NSString*)URLString? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parameters:(id)parameters? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? error:(NSError*__autoreleasing*)error{? ? NSParameterAssert(method);? ? NSParameterAssert(URLString);? ? NSURL*url= [NSURL URLWithString:URLString];? ? NSParameterAssert(url);? ? NSMutableURLRequest*mutableRequest= [[NSMutableURLRequest alloc] initWithURL:url];? ? mutableRequest.HTTPMethod = method;//給mutableRequest賦值剛才在AFHTTPRequestSerializerObservedKeyPaths存儲(chǔ)的屬性,已經(jīng)去掉了空值。for(NSString*keyPathin AFHTTPRequestSerializerObservedKeyPaths()) {if([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {? ? ? ? ? ? [mutableRequest setValue:[selfvalueForKeyPath:keyPath] forKey:keyPath];? ? ? ? }? ? }// 將HTTPRequestHeaders字典屬性中的Header傳給mutableRequest, 將格式化好的queryString傳給mutableRequestmutableRequest = [[selfrequestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];returnmutableRequest;}

剛才的大費(fèi)口舌就是剛好是對這段代碼的解釋。準(zhǔn)備好了request,我們就來看一下如何使用request創(chuàng)建dataTask

2.使用準(zhǔn)備好的mutableRequest對象創(chuàng)建dataTask

在- (NSURLSessionDataTask *)dataTaskWithHTTPMethod: URLString: parameters: failure:方法中的的后半段:

__blockNSURLSessionDataTask*dataTask =nil;dataTask = [selfdataTaskWithRequest:requestcompletionHandler:^(NSURLResponse* __unused response, id responseObject,NSError*error) {//下面會(huì)解讀這一句if(error) {if(failure) {? ? ? ? ? ? failure(dataTask, error);? ? ? ? }? ? }else{if(success) {? ? ? ? ? ? success(dataTask, responseObject);? ? ? ? }? ? }}];returndataTask;

其中的failure和success實(shí)際上是由我們使用者傳遞過來,這段非常簡單的代碼同樣是有點(diǎn)機(jī)關(guān)的,這其中包含了AFN設(shè)計(jì)中使用的將代理職責(zé)轉(zhuǎn)移的思想,盡管我們平常也使用過類似的代碼,但還是研讀一下AFN如何實(shí)現(xiàn)的吧:

上面的dataTask的創(chuàng)建的核心代碼實(shí)現(xiàn)是這樣的:

- (NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)request? ? ? ? ? ? ? ? ? ? ? ? ? ? completionHandler:(void(^)(NSURLResponse*response, id responseObject, NSError*error))completionHandler{? ? __block NSURLSessionDataTask*dataTask= nil;? ? dispatch_sync(url_session_manager_creation_queue(), ^{? ? ? ? dataTask = [self.session dataTaskWithRequest:request];? ? });? ? [selfaddDelegateForDataTask:dataTask completionHandler:completionHandler];//下面有解析returndataTask;}

如上,AFN會(huì)選擇在它自定義的串行隊(duì)列url_session_manager_creation_queue(這個(gè)隊(duì)列標(biāo)記了label:"com.alamofire.networking.session.manager.creation")中采用同步的方式創(chuàng)建dataTask。

在dataTask被創(chuàng)建之后將代理職責(zé)下方給了AFURLSessionManagerTaskDelegate對象,我們可以通過查看[self addDelegateForDataTask:dataTask completionHandler:completionHandler];得出:

- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask? ? ? ? ? ? completionHandler:(void(^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{? ? AFURLSessionManagerTaskDelegate *delegate= [[AFURLSessionManagerTaskDelegate alloc] init];delegate.manager =self;// AFURLSessionManagerTaskDelegate弱引用它的管理者(AFHTTPSessionManager對象)delegate.completionHandler = completionHandler;// 將完成的回調(diào)(failure和success的處理)傳遞給AFURLSessionManagerTaskDelegatedataTask.taskDescription =self.taskDescriptionForSessionTasks;? ? [selfsetDelegate:delegateforTask:dataTask];}

而在的實(shí)現(xiàn)中:

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegateforTask:(NSURLSessionTask *)task{? ? NSParameterAssert(task);? ? NSParameterAssert(delegate);? ? [self.locklock];self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] =delegate;? ? [self.lockunlock];}

這里AFNHTTPSessionManager將單個(gè)dataTask的代理職責(zé)下放給了一個(gè)AFURLSessionManagerTaskDelegate對象,但是這個(gè)對象仍然受manager的控制,manager會(huì)用一個(gè)可變字典類型的屬性mutableTaskDelegatesKeyedByTaskIdentifier存儲(chǔ)它管理的所有的dataTask和這個(gè)dataTask對應(yīng)的AFURLSessionManagerTaskDelegate對象的關(guān)系,而具體的任務(wù)下放就是通過這種關(guān)系來實(shí)現(xiàn)的。

下面就邊介紹數(shù)據(jù)請求與接收的過程階段邊解釋如何通過這種關(guān)系將代理職責(zé)下放。

3.網(wǎng)絡(luò)訪問過程中

這一過程是由dataTask的resume方法開始的。AFHTTPSessionManager的成員session會(huì)使用上面的request進(jìn)行網(wǎng)絡(luò)請求,當(dāng)接收到數(shù)據(jù)之后進(jìn)入回調(diào),AFN已將session在AFHTTPSessionManager的父類AFURLSessionManager中默認(rèn)設(shè)置了self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];并且session的代理方法也已在AFURLSessionManager類中實(shí)現(xiàn)。而AFN在這個(gè)實(shí)現(xiàn)的過程中將每次接收到的數(shù)據(jù)都交給了當(dāng)前dataTask對應(yīng)的AFURLSessionManagerTaskDelegate對象處理,在這里實(shí)現(xiàn)了職責(zé)下放:

在AFURLSessionManager.m中:

- (void)URLSession:(NSURLSession *)session? ? ? ? ? dataTask:(NSURLSessionDataTask *)dataTask? ? didReceiveData:(NSData *)data{? ? AFURLSessionManagerTaskDelegate *delegate= [selfdelegateForTask:dataTask];// 找到dataTask對應(yīng)的AFURLSessionManagerTaskDelegate對象[delegateURLSession:session dataTask:dataTask didReceiveData:data];// 代理職責(zé)下放if(self.dataTaskDidReceiveData) {self.dataTaskDidReceiveData(session, dataTask, data);? ? }}// 如何找到dataTask對應(yīng)的AFURLSessionManagerTaskDelegate對象- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {? ? NSParameterAssert(task);? ? AFURLSessionManagerTaskDelegate *delegate= nil;? ? [self.locklock];delegate=self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];// 根據(jù)taskId,之前以key為taskId、value為AFURLSessionManagerTaskDelegate對象的形式存入字典中。[self.lockunlock];returndelegate;}

而真正處理網(wǎng)絡(luò)請求的類是AFURLSessionManagerTaskDelegate,它從未被設(shè)置為session的delegate,而是在AFHTTPSessionManager(AFURLSessionManager)對session的代理方法的實(shí)現(xiàn)中主動(dòng)調(diào)用。

這個(gè)數(shù)據(jù)最后被這樣處理,在AFURLSessionManagerTaskDelegate中

- (void)URLSession:(__unused NSURLSession*)session? ? ? ? ? dataTask:(__unused NSURLSessionDataTask*)dataTask? ? didReceiveData:(NSData*)data{? ? [self.mutableData appendData:data];}

我們可以看到AFURLSessionManagerTaskDelegate類有一個(gè)mutableData屬性用來拼接接收的數(shù)據(jù)。看一下接收完畢之后是如何處理的,先是在AFURLSessionManager中:

- (void)URLSession:(NSURLSession*)sessiontask:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error{AFURLSessionManagerTaskDelegate*delegate = [selfdelegateForTask:task];//delegate may benilwhencompleting a taskinthe backgroundif(delegate) {? ? ? ? [delegateURLSession:sessiontask:taskdidCompleteWithError:error];? ? ? ? [selfremoveDelegateForTask:task];? ? }if(self.taskDidComplete) {self.taskDidComplete(session, task, error);? ? }}

這里先找到task對應(yīng)的AFURLSessionManagerTaskDelegate對象,同樣是通過dataTask的Id,然后將處理任務(wù)交給這個(gè)delegate對象,等它處理之后,sessionManager會(huì)將這個(gè)delegate對象從字典中移除:

- (void)removeDelegateForTask:(NSURLSessionTask *)task {? ? NSParameterAssert(task);? ? AFURLSessionManagerTaskDelegate *delegate= [selfdelegateForTask:task];? ? [self.locklock];? ? [delegatecleanUpProgressForTask:task];? ? [selfremoveNotificationObserverForTask:task];? ? [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];? ? [self.lockunlock];}

這樣manager管理的session進(jìn)行的一次dataTask就完畢了。

再看一下在AFURLSessionManagerTaskDelegate中,如何具體處理的

- (void)URLSession:(__unusedNSURLSession*)sessiontask:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error{#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wgnu"__strongAFURLSessionManager*manager =self.manager;? ? __block id responseObject =nil;? ? __blockNSMutableDictionary*userInfo = [NSMutableDictionarydictionary];? ? userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;//PerformanceImprovementfrom#2672NSData*data =nil;if(self.mutableData) {? ? ? ? data = [self.mutableData copy];//Weno longer need the reference, sonilit out to gain back some memory.self.mutableData =nil;? ? }if(self.downloadFileURL) {? ? ? ? userInfo[AFNetworkingTaskDidCompleteAssetPathKey] =self.downloadFileURL;? ? }elseif(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(), ^{? ? ? ? ? ? ? ? [[NSNotificationCenterdefaultCenter]postNotificationName:AFNetworkingTaskDidCompleteNotificationobject:taskuserInfo:userInfo];? ? ? ? ? ? });? ? ? ? });? ? }else{? ? ? ? dispatch_async(url_session_manager_processing_queue(), ^{NSError*serializationError =nil;? ? ? ? ? ? responseObject = [manager.responseSerializerresponseObjectForResponse:task.responsedata:dataerror:&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(), ^{? ? ? ? ? ? ? ? ? ? [[NSNotificationCenterdefaultCenter]postNotificationName:AFNetworkingTaskDidCompleteNotificationobject:taskuserInfo:userInfo];? ? ? ? ? ? ? ? });? ? ? ? ? ? });? ? ? ? });? ? }#pragma clang diagnostic pop}

取出SessionManager,和sessionManager的responseSerializer屬性,創(chuàng)建userInfo字典,存放數(shù)據(jù)解析的組件對象和返回的數(shù)據(jù)等

如果有錯(cuò)誤:

1.userInfo存入error,key為完成錯(cuò)誤的標(biāo)記,

2.創(chuàng)建隊(duì)列任務(wù):在主隊(duì)列中完成回調(diào)(由最開始傳入的success和failure處理)、然后向主線程發(fā)送附帶userInfo的任務(wù)完成的通知,

3.將2創(chuàng)建的任務(wù)放在靜態(tài)的隊(duì)列組url_session_manager_completion_group()中執(zhí)行。

沒有錯(cuò)誤:

在異步的靜態(tài)隊(duì)列url_session_manager_processing_queue(label是"com.alamofire.networking.session.manager.processing")中處理:

1.用manager的responseSerializer屬性進(jìn)行數(shù)據(jù)解析,將data解析為responseObject

1.1.解析正確,將responseObject存入userInfo中,

1.2.解析失敗,將錯(cuò)誤信息serializationError存入userInfo,

2.創(chuàng)建隊(duì)列任務(wù):在主隊(duì)列中完成回調(diào)(由最開始傳入的success和failure處理)、然后向主線程發(fā)送附帶userInfo的任務(wù)完成的通知,

3.將2創(chuàng)建的任務(wù)放在靜態(tài)的隊(duì)列組url_session_manager_completion_group()中執(zhí)行。

要說明的一點(diǎn)是:AFN只負(fù)責(zé)發(fā)送通知,而沒有對通知進(jìn)行接收的處理,這部分需要使用者自己完成。現(xiàn)在就只剩下數(shù)據(jù)解析的過程了還沒有介紹了。

4.數(shù)據(jù)解析

這里主要體現(xiàn)的是面向?qū)ο蠖鄳B(tài)的特性。

在無論我們使用AFHTTPSessionManager對象或是使用AFURLSessionManager對象創(chuàng)建的dataTask在數(shù)據(jù)解析階段,都會(huì)調(diào)用上面剛剛分析完的代碼中的responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];這一句進(jìn)行數(shù)據(jù)解析,而在HTTPSessionManager的manager方法中默認(rèn)為我們創(chuàng)建了JSON類型的解析器self.responseSerializer = [AFJSONResponseSerializer serializer];,這樣在執(zhí)行過程中,就會(huì)動(dòng)態(tài)地調(diào)用AFJSONResponseSerializer的-responseObjectForResponse: data: error:方法,它的實(shí)現(xiàn)是這樣的:

- (id)responseObjectForResponse:(NSURLResponse*)response? ? ? ? ? ? ? ? ? ? ? ? ? data:(NSData*)data? ? ? ? ? ? ? ? ? ? ? ? ? error:(NSError*__autoreleasing*)error{if(![selfvalidateResponse:(NSHTTPURLResponse*)response data:data error:error]) {if(!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {returnnil;? ? ? ? }? ? }? ? id responseObject = nil;? ? NSError*serializationError= nil;//Workaroundforbehavior of Rails toreturna single spacefor`head :ok`(a workaroundfora bug in Safari), which isnotinterpreted as valid input by NSJSONSerialization.//See https://github.com/rails/rails/issues/1742BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" "length:1]];if(data.length>0&& !isSpace) {? ? ? ? responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];? ? }else{returnnil;? ? }if(self.removesKeysWithNullValues && responseObject) {? ? ? ? responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject,self.readingOptions);? ? }if(error) {*error= AFErrorWithUnderlyingError(serializationError,*error);? ? }returnresponseObject;}

這是一個(gè)非常簡單的算法,

1.先調(diào)用了從父類(AFHTTPResponseSerializer)集成而來的數(shù)據(jù)驗(yàn)證方法,如果驗(yàn)證失敗了,并且確認(rèn)錯(cuò)誤是由AFN解析引起的,返回nil,

2.檢驗(yàn)data是否為空或者一個(gè)空格這樣的無效數(shù)據(jù),失敗返回nil,否則將data解析為JSONObject

3.如果removesKeysWithNullValues屬性設(shè)置為YES,那么要去掉2中的JSONObject中的value等于[NSNull null]的元素。

AFJSONResponseSerializer類是AFHTTPResponseSerializer的子類,一些初始化的設(shè)置,還有驗(yàn)證數(shù)據(jù)的方法都是在AFJSONResponseSerializer中完成的。

看一下AFJSONResponseSerializer類:

- (instancetype)init {//...self.stringEncoding =NSUTF8StringEncoding;self.acceptableStatusCodes = [NSIndexSetindexSetWithIndexesInRange:NSMakeRange(200,100)];//只接受statusCode為2xxself.acceptableContentTypes =nil;//接收的Content-Type,需要子類的init中重寫returnself;}- (BOOL)validateResponse:(NSHTTPURLResponse*)responsedata:(NSData*)dataerror:(NSError* __autoreleasing *)error{BOOLresponseIsValid =YES;NSError*validationError =nil;if(response && [responseisKindOfClass:[NSHTTPURLResponseclass]]) {if(self.acceptableContentTypes && ![self.acceptableContentTypescontainsObject:[responseMIMEType]]) {if([data length] >0&& [responseURL]) {NSMutableDictionary*mutableUserInfo = [@{NSLocalizedDescriptionKey:[NSStringstringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@",@"AFNetworking",nil), [responseMIMEType]],NSURLErrorFailingURLErrorKey:[responseURL],AFNetworkingOperationFailingURLResponseErrorKey:response,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } mutableCopy];if(data) {? ? ? ? ? ? ? ? ? ? mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? validationError =AFErrorWithUnderlyingError([NSErrorerrorWithDomain:AFURLResponseSerializationErrorDomaincode:NSURLErrorCannotDecodeContentDatauserInfo:mutableUserInfo], validationError);? ? ? ? ? ? }? ? ? ? ? ? responseIsValid =NO;? ? ? ? }if(self.acceptableStatusCodes && ![self.acceptableStatusCodescontainsIndex:(NSUInteger)response.statusCode] && [responseURL]) {NSMutableDictionary*mutableUserInfo = [@{NSLocalizedDescriptionKey:[NSStringstringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)",@"AFNetworking",nil), [NSHTTPURLResponselocalizedStringForStatusCode:response.statusCode], (long)response.statusCode],NSURLErrorFailingURLErrorKey:[responseURL],AFNetworkingOperationFailingURLResponseErrorKey:response,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } mutableCopy];if(data) {? ? ? ? ? ? ? ? mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;? ? ? ? ? ? }? ? ? ? ? ? validationError =AFErrorWithUnderlyingError([NSErrorerrorWithDomain:AFURLResponseSerializationErrorDomaincode:NSURLErrorBadServerResponseuserInfo:mutableUserInfo], validationError);? ? ? ? ? ? responseIsValid =NO;? ? ? ? }? ? }if(error && !responseIsValid) {? ? ? ? *error = validationError;? ? }returnresponseIsValid;}

init不再多說,主要是驗(yàn)證方法- (BOOL)validateResponse: data: error:,在這個(gè)方法內(nèi)部完成了這些工作:

1.設(shè)置驗(yàn)證通過responseIsValid的默認(rèn)值YES,錯(cuò)誤validationError為nil

2.驗(yàn)證

2.1對response的MIME類型驗(yàn)證:如果acceptableContentTypes屬性中不包含response的MIME類型,則認(rèn)為驗(yàn)證失敗,responseIsValid設(shè)為NO,本地化錯(cuò)誤描述,并將描述、response的URL、response對象存入userInfo字典,用這個(gè)userInfo字典創(chuàng)建Domain為AFURLResponseSerializationErrorDomain的NSError對象

2.2對response.statusCode驗(yàn)證:如果acceptableStatusCodes屬性中不包含response.statusCode,則認(rèn)為失敗,處理同2.1,

3.將錯(cuò)誤賦給參數(shù)error,返回responseIsValid。

對于其他類型的解析與JSON類似這里列舉一下經(jīng)過解析后的的id responseObject對應(yīng)的類型:

manager的responseSerializer屬性類型解析后的responseObject類型

AFHTTPResponseSerializerNSData

AFJSONResponseSerializerJSONObject(NSDictionary或NSArray)

AFXMLParserResponseSerializerNSXMLParser

AFXMLDocumentResponseSerializerNSXMLDocument

AFPropertyListResponseSerializerpropertyList(NSDictionary或NSArray)

AFImageResponseSerializeriOS、TV、Watch:UIImage Mac:NSImage

AFCompoundResponseSerializer用responseSerializers數(shù)組中對象依次解析,第一個(gè)失敗,則用第二個(gè)解析,依次類推,返回第一個(gè)成功的結(jié)果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容