美文网首页Vender
AFNetworking源码分析(4)--AFURLRespon

AFNetworking源码分析(4)--AFURLRespon

作者: Arnold134777 | 来源:发表于2017-07-02 21:03 被阅读47次

    系列文章:

    本文我们将继续分析下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

    派生类中我们重点分析AFJSONResponseSerializerAFCompoundResponseSerializer,首先看看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];
    }
    

    其他的派生类就不再分别作分析,有兴趣可以自己了解。

    相关文章

      网友评论

        本文标题:AFNetworking源码分析(4)--AFURLRespon

        本文链接:https://www.haomeiwen.com/subject/rksocxtx.html