系列文章:
本文我们将继续分析下AFNetworking
中关于响应数据序列化的处理类——AFURLResponseSerialization
。
代码结构
[-] AFURLResponseSerialization/
[-] AFURLResponseSerialization / 响应解析的协议
[-] AFHTTPResponseSerializer / 响应序列化的基类
[-] AFJSONResponseSerializer / 响应数据是json格式的序列化类
[-] AFXMLParserResponseSerializer / 响应的数据是xml格式的序列化类
[-] AFXMLDocumentResponseSerializer / 响应数据是xmlDocument格式的序列化类
[-] AFPropertyListResponseSerializer / 响应数据是plist格式的序列化类
[-] AFImageResponseSerializer / 响应数据是image格式的序列化类
[-] AFCompoundResponseSerializer / 响应数据是复合的数据类型的序列化类
首先我们先分析一下基类的对外接口与处理逻辑。
AFHTTPResponseSerializer
初始化
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
// 1.指定响应数据的序列化的编码格式utf-8
self.stringEncoding = NSUTF8StringEncoding;
// 2.设置默认接收的服务端成功的code码集合
self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
self.acceptableContentTypes = nil;
return self;
}
数据校验
我们查看派生的几个响应序列化的类中都会在AFURLResponseSerialization
实现的协议接口中调用如下的接口实现校验数据:
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
data:(nullable NSData *)data
error:(NSError * _Nullable __autoreleasing *)error;
下面我们来分析一下它内部具体是如何实现的:
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
{
BOOL responseIsValid = YES;
NSError *validationError = nil;
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
// 1.设置的数据的接受类型不为空且真实响应数据类型不存在其中且(响应的数据`MIMEType`不为空或者响应数据data不为空)
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
!([response MIMEType] == nil && [data length] == 0)) {
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;
}
// 2.数据的响应的code码集合存在且返回数据code码不在其中
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;
}
AFJSONResponseSerializer
派生类中我们重点分析AFJSONResponseSerializer
与AFCompoundResponseSerializer
,首先看看AFJSONResponseSerializer
。
初始化
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
// 1.设置接收的响应的数据类型集合
self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
处理响应数据
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
// 1.数据校验
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/1742
// 2.排除返回数据只有一个空格的情况,然后完成序列化数据
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length > 0 && !isSpace) {
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
return nil;
}
// 3.外部设置了`removesKeysWithNullValues=YES`时,递归的方式处理value为null的情况
if (self.removesKeysWithNullValues && responseObject) {
responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return responseObject;
}
AFCompoundResponseSerializer
这个类的设计是为了处理响应的数据可能存在多种不同的类型的情况,我们来看看具体实现:
外部
提供了一个数组属性,外部可以指定多种序列化数据的类。
/**
The component response serializers.
*/
@property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;
处理响应数据
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
// 遍历外部指定的响应序列化类的集合,依次序列化响应数据,成功序列化就直接返回序列化数据
for (id <AFURLResponseSerialization> serializer in self.responseSerializers) {
if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) {
continue;
}
NSError *serializerError = nil;
id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError];
if (responseObject) {
if (error) {
*error = AFErrorWithUnderlyingError(serializerError, *error);
}
return responseObject;
}
}
return [super responseObjectForResponse:response data:data error:error];
}
其他的派生类就不再分别作分析,有兴趣可以自己了解。