AFN3.2第4篇-AFURLResponseSerialization

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.");

// [[alloc] init], 不是单例
+ (instancetype)serializer;

//设置的状态码,范围:默认的是[200,300)的范围为正常的成功响应
//NSIndexSet是一个有序的,唯一的,无符号整数的集合。
@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
//设置接受的内容类型:默认为nil
@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]]) {
        //递归遍历数组,通过迭代的手段清空数组内的null
        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]]) {

        //判断: 有数据,但是返回的mimeType不在预设的contentType里面
        if (self.acceptableContentTypes &&
            ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
            !([response MIMEType] == nil && [data length] == 0)) {

            //error封装处理
            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)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值