AFURLResponseSerialization 目录
AFURLResponseSerialization结构
protocol: AFURLResponseSerialization
class: AFHTTPResponseSerializer
AFJSONResponseSerializer
AFXMLParserResponseSerializer
AFPropertyListResponseSerializer
AFImageResponseSerializer
AFCompoundResponseSerializer
AFURLResponseSerialization.h
@protocol AFURLResponseSerialization <NSObject, NSSecureCoding, NSCopying>
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response data:(nullable NSData *)data error:(NSError * _Nullable __autoreleasing *)error;
@end
#pragma mark - ========== AFHTTPResponseSerializer ==========
@interface AFHTTPResponseSerializer : NSObject <AFURLResponseSerialization>
- (instancetype)init;
@property (nonatomic, assign) NSStringEncoding stringEncoding DEPRECATED_MSG_ATTRIBUTE("The string encoding is never used. AFHTTPResponseSerializer only validates status codes and content types but does not try to decode the received data in any way.");
+ (instancetype)serializer;
@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
data:(nullable NSData *)data
error:(NSError * _Nullable __autoreleasing *)error;
@end
#pragma mark - ========== AFJSONResponseSerializer ==========
@interface AFJSONResponseSerializer : AFHTTPResponseSerializer
- (instancetype)init;
@property (nonatomic, assign) NSJSONReadingOptions readingOptions;
@property (nonatomic, assign) BOOL removesKeysWithNullValues;
+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions;
@end
#pragma mark - ========== AFXMLParserResponseSerializer ==========
@interface AFXMLParserResponseSerializer : AFHTTPResponseSerializer
@end
#pragma mark - ========== AFXMLDocumentResponseSerializer ==========
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
@interface AFXMLDocumentResponseSerializer : AFHTTPResponseSerializer
- (instancetype)init;
@property (nonatomic, assign) NSUInteger options;
+ (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask;
@end
#endif
#pragma mark - ========== AFPropertyListResponseSerializer ==========
@interface AFPropertyListResponseSerializer : AFHTTPResponseSerializer
- (instancetype)init;
@property (nonatomic, assign) NSPropertyListFormat format;
@property (nonatomic, assign) NSPropertyListReadOptions readOptions;
+ (instancetype)serializerWithFormat:(NSPropertyListFormat)format
readOptions:(NSPropertyListReadOptions)readOptions;
@end
#pragma mark - ========== AFImageResponseSerializer ==========
@interface AFImageResponseSerializer : AFHTTPResponseSerializer
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
@property (nonatomic, assign) CGFloat imageScale;
@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage;
#endif
@end
#pragma mark - ========== AFCompoundResponseSerializer ==========
@interface AFCompoundResponseSerializer : AFHTTPResponseSerializer
@property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;
+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray <id<AFURLResponseSerialization>> *)responseSerializers;
@end
FOUNDATION_EXPORT NSString * const AFURLResponseSerializationErrorDomain;
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseErrorKey;
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
AFURLResponseSerialization.m
对Error的封装处理
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
if (!error) {
return underlyingError;
}
if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) {
return error;
}
NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy];
mutableUserInfo[NSUnderlyingErrorKey] = underlyingError;
return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];
}
static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {
if ([error.domain isEqualToString:domain] && error.code == code) {
return YES;
} else if (error.userInfo[NSUnderlyingErrorKey]) {
return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);
}
return NO;
}
去除null
static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {
if ([JSONObject isKindOfClass:[NSArray class]]) {
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];
for (id value in (NSArray *)JSONObject) {
[mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)];
}
return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];
} else if ([JSONObject isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];
for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {
id value = (NSDictionary *)JSONObject[key];
if (!value || [value isEqual:[NSNull null]]) {
[mutableDictionary removeObjectForKey:key];
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions);
}
}
return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
return JSONObject;
}
验证response的有效性
- (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]) {
NSString *descriptionKey = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]];
NSMutableDictionary *mutableUserInfo =
[@{NSLocalizedDescriptionKey:descriptionKey, 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]) {
NSString *descriptionKey = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode];
NSMutableDictionary *mutableUserInfo =
[@{NSLocalizedDescriptionKey:descriptionKey, 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
- 默认使用的readingOptions: NSJSONReadingMutableContainers
- 默认acceptableContentTypes = [NSSet setWithObjects:@”application/json”, @”text/json”, @”text/javascript”, nil];
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error {
// 判空处理,如果验证结果失败,在没有error 或者 错误中..
// ..code:NSURLErrorCannotDecodeContentData 的情况下,是不能解析数据的,就返回nil
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
return nil;
}
}
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length == 0 || isSpace) {
return nil;
}
/*
在之前的版本中出现过尝试用HTTP返回的编码类型和自己设置的stringEncoding去把数据解码转成字符串NSString,再把NSString用UTF8编码转成NSData,再用NSJSONSerialization解析成对象返回。 因为AFJSONResponseSerializer使用系统内置的NSJSONSerialization解析json,NSJSON只支持解析UTF8编码的数据(还有UTF-16LE之类的,都不常用),所以要先把返回的数据转成UTF8格式。
*/
NSError *serializationError = nil;
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
if (!responseObject) {
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return nil;
}
if (self.removesKeysWithNullValues) {
return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}
return responseObject;
}
AFURLResponseSerialization总结
- AFURLResponseSerialization对JSON对象的解析核心还是调用系统的API
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
- 返回的对象我们通常习惯性的判空为nil,AFN贴心的去除掉了null的返回对象,
- 验证有效响应主要靠: MIMEType和statusCode;也就是判断返回的对象数据类型是否为可接受的类型,HTTP状态响应码是否为可接受的范围:默认是[200, 300)。