ios AFNetworking 3.0 原码阅读分析 (二)(AFURLResponseSerialization模块)

  回顾上篇写的AFURLRequestSerialization接下来要写的AFURLResponseSerialization还是相对简单的,所以内容也较简短。它的主要作用是为我们请求所得到的数提供验证并提供返序列化的方式。我们只需要按自己的需求选择合适的AFURLResponseSerialization即可,反序列成功后就能得我们想要的结果。


 

  首先看一下在AFURLResponseSerialization.h和AFURLResponseSerialization.m中所包含的类及它们间的关系。

它们之间的关系还是比较简单的,每个子类对应于一种反序列化的方式

接下来主要讲一下细节方面

AFURLResponseSerialization:AFURLResponseSerialization协议,它定义了以下方法,供每个子类实现自己的行为。

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error;

AFHTTPResponseSerializer:它是其它各个子类的基类。它里面的属性及方法并不多。

//默认是200到299
@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;

///每个AFHTTPResponseSerializer子类会有自己的默认可接受类型,具体看它及每个子类的init初始化方法
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;

//这个方法比较重要,因为AFHTTPResponseSerializer及所有AFHTTPResponseSerializer子类验证数据的有效性都是调到到AFHTTPResponseSerializer的这个方法。
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
                    data:(nullable NSData *)data
                   error:(NSError * _Nullable __autoreleasing *)error;

接下来我们看一下validateResponse:data:error:的源码实现

- (BOOL)validateResponse:(NSHTTPURLResponse *)response
                    data:(NSData *)data
                   error:(NSError * __autoreleasing *)error
{
    BOOL responseIsValid = YES; //默认是有效的
    NSError *validationError = nil;
    //如果是NSHTTPURLResponse类
    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]) {
            
                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;
}

逻辑也并不复杂,这里有些地方代码太长,不太好弄得好看,可以对用XCode对着源码看。这里重点关注一下加粗的方法AFErrorWithUnderlyingError。

//两个error,如果有需要,把underlyingError作为error的子错误
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
    //如果error为空,直接返回underlyingError
    if (!error) {
        return underlyingError;
    }
    
    //如果underlyingError为空或者error的userInfo[error.userInfo[NSUnderlyingErrorKey]]已经有值,
  直接返回error
if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) { return error; } //拿到error的userInfo,加上一个值为mutableUserInfo[NSUnderlyingErrorKey] = underlyingError,
  即把underlying放到了error中userInfo中。
NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy]; mutableUserInfo[NSUnderlyingErrorKey] = underlyingError; return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo]; }

到这AFHTTPResponseSerializer也就讲完了。

剩下的都是AFHTTPResponseSerializer的子类了,它们都是在自己实现的responseObjectForResponse:data:error:方法中先校验数据的有效性,再对数据进行反序列化,得到结果,没什么好写的了,直接看源码即可。


  到这里就把AFURLResponseSerialization介绍完了,主要讲了它提供的功能,它的基本实现原理细节,对于其它各子类的其它细节内容就不在这展开了。

 

posted on 2016-07-22 16:59  chenxianming  阅读(1006)  评论(0编辑  收藏  举报

导航