全包网站,做网站采集,高端网站建设域名注册,新手做淘宝哪个网站比较好流程梳理 今天开始会写几篇关于AFN源码解读的一些Blog#xff0c;首先要梳理一下AFN的整体结构(主要是讨论2.x版本的Session访问模块)#xff1a; 我们先看看我们最常用的一段代码#xff1a; AFHTTPSessionManager *manager [AFHTTPSessionManager manager];
[manager GET… 流程梳理 今天开始会写几篇关于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后面.如果是POSTPUTPATCH方法则放在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(这个队列标记了labelcom.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存入errorkey为完成错误的标记 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类型AFHTTPResponseSerializerNSDataAFJSONResponseSerializerJSONObject(NSDictionary或NSArray)AFXMLParserResponseSerializerNSXMLParserAFXMLDocumentResponseSerializerNSXMLDocumentAFPropertyListResponseSerializerpropertyList(NSDictionary或NSArray)AFImageResponseSerializeriOS、TV、Watch:UIImage Mac:NSImageAFCompoundResponseSerializer用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