日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

通读AFN①--从创建manager到数据解析完毕

發布時間:2023/12/9 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通读AFN①--从创建manager到数据解析完毕 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

流程梳理

今天開始會寫幾篇關于AFN源碼解讀的一些Blog,首先要梳理一下AFN的整體結構(主要是討論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 }];

在前面關于 AFN URLEncode 的文章說道,AFN將網絡訪問分為三個過程化的模塊,下面我把第一部分再分為兩個步驟:

1.訪問前的準備:使用AFURLRequestSerialization類創建一個新的URLRequest對象(用于即將進行的網絡訪問),對傳遞過來的URLrequest對象進行三步加工:
①配置默認網絡配置,如(allowsCellularAccess,cachePolicy,HTTPShouldHandleCookies,HTTPShouldUsePipelining,networkServiceType,timeoutInterval)
②將request的HTTPHeader賦給新的request
③將parameter字典轉為queryString,拼接在URLRequest的URL后面.如果是POST,PUT,PATCH方法,則放在HTTPBody中,并設置Content-Type頭為表單類型:application/x-www-form-urlencoded

2.用1中所得的mutableRequest對象創建dataTask

3.訪問過程中,將代理職責下放給AFURLSessionManagerTaskDelegate,通過代理方法接收數據。

4.完全接受到數據或失敗之后的處理:失敗回調、成功后解析然后回調。

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

self.baseURL = url;self.requestSerializer = [AFHTTPRequestSerializer serializer]; self.responseSerializer = [AFJSONResponseSerializer serializer];

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

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按照什么格式序列化,還可以改變默認的session配置,進行創建Task的session對象在AFN中成為了AFHTTPSessionManager的屬性,如果不使用構造方法- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration 傳給它一個值,它會在AFHTTPSessionManager的父類AFURLRequestSerialization中默認配置的,不光如此,而且還配置了AFHTTPSessionManager的很多重要屬性,在AFURLRequestSerialization的-initWithBaseURL: sessionConfiguration:中:

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];self.lock = [[NSLock alloc] init]; self.lock.name = AFURLSessionManagerLockName;[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {for (NSURLSessionDataTask *task in dataTasks) {[self addDelegateForDataTask:task 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];} }];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];return self;

這些默認的配置大多是不可以在外部修改,因為大都為readonly屬性,只是在實現文件中給了修改的接口。例如:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; // 設置最大并發操作數 manager.operationQueue.maxConcurrentOperationCount = 3; // error [manager GET: parameter: success: failure:];

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

1.訪問前的準備:使用AFURLRequestSerialization類創建一個新的URLRequest對象

這一部分的很多知識點,在這篇文章 iOS. PercentEscape是錯用的URLEncode,看看AFN和Facebook吧中有介紹,這里說一些補充的內容:
首先是requestSerializer的創建細節:這個雖然不屬于這部分內容(它是在+manager方法中就創建了),但有些問題還需注意:

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

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

為什么要KVO以上6個屬性?

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

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

下面我們就看一下mutableRequest創建的細節吧:

- (NSMutableURLRequest *)requestWithMethod:(NSString *)methodURLString:(NSString *)URLStringparameters:(id)parameterserror:(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存儲的屬性,已經去掉了空值。for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];}}// 將HTTPRequestHeaders字典屬性中的Header傳給mutableRequest, 將格式化好的queryString傳給mutableRequestmutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];return mutableRequest; }

剛才的大費口舌就是剛好是對這段代碼的解釋。
準備好了request,我們就來看一下如何使用request創建dataTask

2.使用準備好的mutableRequest對象創建dataTask

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

__block NSURLSessionDataTask *dataTask = nil; dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { // 下面會解讀這一句if (error) {if (failure) {failure(dataTask, error);}} else {if (success) {success(dataTask, responseObject);}} }];return dataTask;

其中的failure和success實際上是由我們使用者傳遞過來,這段非常簡單的代碼同樣是有點機關的,這其中包含了AFN設計中使用的將代理職責轉移的思想,盡管我們平常也使用過類似的代碼,但還是研讀一下AFN如何實現的吧:

上面的dataTask的創建的核心代碼實現是這樣的:

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

如上,AFN會選擇在它自定義的串行隊列url_session_manager_creation_queue(這個隊列標記了label:"com.alamofire.networking.session.manager.creation")中采用同步的方式創建dataTask。
在dataTask被創建之后將代理職責下方給了AFURLSessionManagerTaskDelegate對象,我們可以通過查看[self addDelegateForDataTask:dataTask completionHandler:completionHandler];得出:

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

而在的實現中:

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

這里AFNHTTPSessionManager將單個dataTask的代理職責下放給了一個AFURLSessionManagerTaskDelegate對象,但是這個對象仍然受manager的控制,manager會用一個可變字典類型的屬性mutableTaskDelegatesKeyedByTaskIdentifier存儲它管理的所有的dataTask和這個dataTask對應的AFURLSessionManagerTaskDelegate對象的關系,而具體的任務下放就是通過這種關系來實現的。

下面就邊介紹數據請求與接收的過程階段邊解釋如何通過這種關系將代理職責下放。

3.網絡訪問過程中

這一過程是由dataTask的resume方法開始的。AFHTTPSessionManager的成員session會使用上面的request進行網絡請求,當接收到數據之后進入回調,AFN已將session在AFHTTPSessionManager的父類AFURLSessionManager中默認設置了self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];并且session的代理方法也已在AFURLSessionManager類中實現。而AFN在這個實現的過程中將每次接收到的數據都交給了當前dataTask對應的AFURLSessionManagerTaskDelegate對象處理,在這里實現了職責下放:
在AFURLSessionManager.m中:

- (void)URLSession:(NSURLSession *)sessiondataTask:(NSURLSessionDataTask *)dataTaskdidReceiveData:(NSData *)data {AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; // 找到dataTask對應的AFURLSessionManagerTaskDelegate對象[delegate URLSession:session dataTask:dataTask didReceiveData:data]; // 代理職責下放if (self.dataTaskDidReceiveData) {self.dataTaskDidReceiveData(session, dataTask, data);} }// 如何找到dataTask對應的AFURLSessionManagerTaskDelegate對象 - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {NSParameterAssert(task);AFURLSessionManagerTaskDelegate *delegate = nil;[self.lock lock];delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)]; // 根據taskId,之前以key為taskId、value為AFURLSessionManagerTaskDelegate對象的形式存入字典中。[self.lock unlock];return delegate; }

而真正處理網絡請求的類是AFURLSessionManagerTaskDelegate,它從未被設置為session的delegate,而是在AFHTTPSessionManager(AFURLSessionManager)對session的代理方法的實現中主動調用。

這個數據最后被這樣處理,在AFURLSessionManagerTaskDelegate中

- (void)URLSession:(__unused NSURLSession *)sessiondataTask:(__unused NSURLSessionDataTask *)dataTaskdidReceiveData:(NSData *)data {[self.mutableData appendData:data]; }

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

- (void)URLSession:(NSURLSession *)sessiontask:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];// delegate may be nil when completing a task in the backgroundif (delegate) {[delegate URLSession:session task:task didCompleteWithError:error];[self removeDelegateForTask:task];}if (self.taskDidComplete) {self.taskDidComplete(session, task, error);} }

這里先找到task對應的AFURLSessionManagerTaskDelegate對象,同樣是通過dataTask的Id,然后將處理任務交給這個delegate對象,等它處理之后,sessionManager會將這個delegate對象從字典中移除:

- (void)removeDelegateForTask:(NSURLSessionTask *)task {NSParameterAssert(task);AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];[self.lock lock];[delegate cleanUpProgressForTask:task];[self removeNotificationObserverForTask:task];[self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];[self.lock unlock]; }

這樣manager管理的session進行的一次dataTask就完畢了。

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

- (void)URLSession:(__unused NSURLSession *)sessiontask:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu"__strong AFURLSessionManager *manager = self.manager;__block id responseObject = nil;__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;//Performance Improvement from #2672NSData *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.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];});});});} #pragma clang diagnostic pop }

取出SessionManager,和sessionManager的responseSerializer屬性,創建userInfo字典,存放數據解析的組件對象和返回的數據等

如果有錯誤:
1.userInfo存入error,key為完成錯誤的標記,
2.創建隊列任務:在主隊列中完成回調(由最開始傳入的success和failure處理)、然后向主線程發送附帶userInfo的任務完成的通知,
3.將2創建的任務放在靜態的隊列組url_session_manager_completion_group()中執行。

沒有錯誤:
在異步的靜態隊列url_session_manager_processing_queue(label是"com.alamofire.networking.session.manager.processing")中處理:
1.用manager的responseSerializer屬性進行數據解析,將data解析為responseObject
1.1.解析正確,將responseObject存入userInfo中,
1.2.解析失敗,將錯誤信息serializationError存入userInfo,
2.創建隊列任務:在主隊列中完成回調(由最開始傳入的success和failure處理)、然后向主線程發送附帶userInfo的任務完成的通知,
3.將2創建的任務放在靜態的隊列組url_session_manager_completion_group()中執行。

要說明的一點是:AFN只負責發送通知,而沒有對通知進行接收的處理,這部分需要使用者自己完成。
現在就只剩下數據解析的過程了還沒有介紹了。

4.數據解析

這里主要體現的是面向對象多態的特性。
在無論我們使用AFHTTPSessionManager對象或是使用AFURLSessionManager對象創建的dataTask在數據解析階段,都會調用上面剛剛分析完的代碼中的responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];這一句進行數據解析,而在HTTPSessionManager的manager方法中默認為我們創建了JSON類型的解析器self.responseSerializer = [AFJSONResponseSerializer serializer];,這樣在執行過程中,就會動態地調用AFJSONResponseSerializer的-responseObjectForResponse: data: error:方法,它的實現是這樣的:

- (id)responseObjectForResponse:(NSURLResponse *)responsedata:(NSData *)dataerror:(NSError *__autoreleasing *)error {if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {return nil;}}id responseObject = nil;NSError *serializationError = nil;// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted 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 {return nil;}if (self.removesKeysWithNullValues && responseObject) {responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);}if (error) {*error = AFErrorWithUnderlyingError(serializationError, *error);}return responseObject; }

這是一個非常簡單的算法,
1.先調用了從父類(AFHTTPResponseSerializer)集成而來的數據驗證方法,如果驗證失敗了,并且確認錯誤是由AFN解析引起的,返回nil,
2.檢驗data是否為空或者一個空格這樣的無效數據,失敗返回nil,否則將data解析為JSONObject
3.如果removesKeysWithNullValues屬性設置為YES,那么要去掉2中的JSONObject中的value等于[NSNull null]的元素。

AFJSONResponseSerializer類是AFHTTPResponseSerializer的子類,一些初始化的設置,還有驗證數據的方法都是在AFJSONResponseSerializer中完成的。

看一下AFJSONResponseSerializer類:

- (instancetype)init {// ...self.stringEncoding = NSUTF8StringEncoding;self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; // 只接受statusCode為2xxself.acceptableContentTypes = nil; // 接收的Content-Type,需要子類的init中重寫return self; }- (BOOL)validateResponse:(NSHTTPURLResponse *)responsedata:(NSData *)dataerror:(NSError * __autoreleasing *)error {BOOL responseIsValid = YES;NSError *validationError = nil;if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) {if ([data length] > 0 && [response URL]) {NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],NSURLErrorFailingURLErrorKey:[response URL],AFNetworkingOperationFailingURLResponseErrorKey: response,} mutableCopy];if (data) {mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;}validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);}responseIsValid = NO;}if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],NSURLErrorFailingURLErrorKey:[response URL],AFNetworkingOperationFailingURLResponseErrorKey: response,} mutableCopy];if (data) {mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;}validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);responseIsValid = NO;}}if (error && !responseIsValid) {*error = validationError;}return responseIsValid; }

init不再多說,主要是驗證方法- (BOOL)validateResponse: data: error:,在這個方法內部完成了這些工作:
1.設置驗證通過responseIsValid的默認值YES,錯誤validationError為nil
2.驗證
?2.1對response的MIME類型驗證:如果acceptableContentTypes屬性中不包含response的MIME類型,則認為驗證失敗,responseIsValid設為NO,本地化錯誤描述,并將描述、response的URL、response對象存入userInfo字典,用這個userInfo字典創建Domain為AFURLResponseSerializationErrorDomain的NSError對象
?2.2對response.statusCode驗證:如果acceptableStatusCodes屬性中不包含response.statusCode,則認為失敗,處理同2.1,
3.將錯誤賦給參數error,返回responseIsValid。


對于其他類型的解析與JSON類似,這里列舉一下經過解析后的的id responseObject對應的類型:

manager的responseSerializer屬性類型解析后的responseObject類型
AFHTTPResponseSerializerNSData
AFJSONResponseSerializerJSONObject(NSDictionary或NSArray)
AFXMLParserResponseSerializerNSXMLParser
AFXMLDocumentResponseSerializerNSXMLDocument
AFPropertyListResponseSerializerpropertyList(NSDictionary或NSArray)
AFImageResponseSerializeriOS、TV、Watch:UIImage ?? Mac:NSImage
AFCompoundResponseSerializer用responseSerializers數組中對象依次解析,
第一個失敗,則用第二個解析,依次類推,返回第一個成功的結果

當獲取responseObject對象后,直接按類型使用即可,例如如果設置了manager.responseSerializer = [AFXMLParserResponseSerializer serializer],就要這樣解析:

success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSXMLParser *saxParser = (NSXMLParser *)responseObject;saxParser.delegate = self;[saxParser parse]; }

不過若要使用相同的manager對象進行下一次網絡訪問,如果不知道response的Content-Type,就要將manager的responseSerializer復原,重新設置為:

manager.responseSerializer = [AFJSONRequestSerializer serializer]; // 如果manager為AFHTTPSessionManager manager.responseSerializer = [AFHTTPRequestSerializer serializer]; // 如果manager為AFURLSessionManager

轉載于:https://www.cnblogs.com/Mike-zh/p/5167017.html

總結

以上是生活随笔為你收集整理的通读AFN①--从创建manager到数据解析完毕的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。