AFNetworking 3.0 源码解析之Serializat

作者: SemyonXu | 来源:发表于2016-10-07 21:34 被阅读345次

    本部分主要的作用:网络通信信息序列化/反序列化

    AFURLRequestSerialization

    功能:

    负责参数转换成NSMutableURLRequest类型,进行网络请求。

    1. 构建普通请求:格式化请求参数,生成HTTP Header
    2. 构建multipart请求

    类关系:

    父类:

    • AFHTTPRequestSerializer,二进制格式(query字符串转换成二进制)

    子类:

    • AFJSONRequestSerializer,Json格式(Json序列化成NSData类型)
    • AFPropertyListRequestSerializer,Plist(一种特殊的XML,解析起来相对容易)

    封装思路:

    所有类遵循一个协议AFURLRequestSerialization,协议中一个非必须实现的方法:

     - (nullableNSURLRequest*)requestBySerializingRequest:(NSURLRequest*)request
                                     withParameters:(nullableid)parameters
                                        error:(NSError* _Nullable__autoreleasing *)error NS_SWIFT_NOTHROW;
    

    父类AFHTTPRequestSerializer中提供外部调用接口:

    - (NSMutableURLRequest*)requestWithMethod:(NSString*)method
                                     URLString:(NSString*)URLString
                                    parameters:(id)parameters
                                         error:(NSError*__autoreleasing*)error
    

    在这个方法中调用协议方法:

    mutableRequest = [[selfrequestBySerializingRequest:mutableRequestwithParameters:parameterserror:error]mutableCopy];
    

    而这个方法的实现是父类以及各个子类分别实现。所以,此处self如果是AFHTTPRequestSerializer那么走AFHTTPRequestSerializer类下的实现,如果是
    AFJSONRequestSerializer,那么走AFJSONRequestSerializer类下的实现。然后再分别实现这个方法不同功能的实现。

    下面看一下各个类不同职能分别的实现:

    AFURLRequestSerialization中的实现:

    - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                                   withParameters:(id)parameters
                                            error:(NSError *__autoreleasing *)error
    {
        NSParameterAssert(request);
    
        NSMutableURLRequest *mutableRequest = [requestmutableCopy];
    
        [self.HTTPRequestHeadersenumerateKeysAndObjectsUsingBlock:^(id field,id value, BOOL *__unused stop) {
            if (![requestvalueForHTTPHeaderField:field]) {
                [mutableRequest setValue:valueforHTTPHeaderField:field];
            }
        }];
    
        NSString *query =nil;
        if (parameters) {
            if (self.queryStringSerialization) {
                NSError *serializationError;
                query = self.queryStringSerialization(request, parameters, &serializationError);
    
                if (serializationError) {
                    if (error) {
                        *error = serializationError;
                    }
    
                    returnnil;
                }
            } else {
                switch (self.queryStringSerializationStyle) {
                    caseAFHTTPRequestQueryStringDefaultStyle:
                        query = AFQueryStringFromParameters(parameters);
                        break;
                }
            }
        }
    
        if ([self.HTTPMethodsEncodingParametersInURIcontainsObject:[[request HTTPMethod]uppercaseString]]) { //普通GET,HEAD等,参数直接拼接在url后面用&分开
            if (query && query.length >0) {
                mutableRequest.URL = [NSURLURLWithString:[[mutableRequest.URLabsoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
            }
        } else {
            // #2864: an empty string is a valid x-www-form-urlencoded payload
            if (!query) {
                query = @"";
            }
            if (![mutableRequestvalueForHTTPHeaderField:@"Content-Type"]) {
                [mutableRequest setValue:@"application/x-www-form-urlencoded"forHTTPHeaderField:@"Content-Type"];
            }
            [mutableRequest setHTTPBody:[querydataUsingEncoding:self.stringEncoding]];// 普通的POST请求参数,直接转换成NSData设置到HTTP的body中。
        }
    
        return mutableRequest;
    }
    

    我们可以看到AFNetworking对于GET,POST请求参数的处理,一个是直接拼接在URL上面,一个是设置在HTTPBody里面。

    其中,HTTPMethodsEncodingParametersInURI的初始化如下:

    self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil]; // 支持GET,HEAD,DELETE
    

    也就是GET,HEAD,DELETE支持的是参数直接拼接URL的方式。

    AFJSONRequestSerialization中的实现:

    - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                                   withParameters:(id)parameters
                                            error:(NSError *__autoreleasing *)error
    {
        NSParameterAssert(request);
    
        if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
            return [super requestBySerializingRequest:request withParameters:parameters error:error];
        }
    
        NSMutableURLRequest *mutableRequest = [request mutableCopy];
    
        [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
            if (![request valueForHTTPHeaderField:field]) {
                [mutableRequest setValue:value forHTTPHeaderField:field];
            }
        }]; // 设置公共的请求头
    
        if (parameters) {
            if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
                [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
            }
    
            [mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
        }
    
        return mutableRequest;
    }
    

    跟AFURLRequestSerialization中的实现差不多,如果是HTTPMethodsEncodingParametersInURI请求方式是GET,HEAD,DELETE,则直接调用父类的解析方法。如果是POST等其他的,那么做了一下设置请求头Content-Type = “application/json”,并且将paramters参数Json序列化成NSData,设置到HTTPBody里面。

    AFPropertyListRequestSerialization中的实现:

    - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                                   withParameters:(id)parameters
                                            error:(NSError *__autoreleasing *)error
    {
        NSParameterAssert(request);
    
        if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
            return [super requestBySerializingRequest:request withParameters:parameters error:error];
        }
    
        NSMutableURLRequest *mutableRequest = [request mutableCopy];
    
        [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
            if (![request valueForHTTPHeaderField:field]) {
                [mutableRequest setValue:value forHTTPHeaderField:field];
            }
        }];
    
        if (parameters) {
            if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
                [mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];
            }
    
            [mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]];
        }
    
        return mutableRequest;
    }
    

    好吧,封装思路跟AFJSONRequestSerialization一样,区别在于json序列化变成Plist的转换。

    AFURLResponseSerialization

    功能:

    负责对网络请求返回的数据进行解析。

    类关系:

    父类:

    • AFHTTPResponseSerializer,二进制格式

    子类:

    • AFJSONResponseSerializer, JSON格式
    • AFXMLParseResponseSerializer, XML(只能返回XMLParser,还需要自己通过代理解析)
    • AFXMLDocumentResponseSerializer, (Mac OS X)
    • AFPropertyListResponseSerializer, Plist
    • AFImageResponseSerializer, Image
    • AFCompoundResponseSerializer, 组合

    封装思路:

    跟Request的封装思路基本相同。只不过这个是在数据请求到之后进行的处理。遵循的是AFURLResponseSerialization协议。实现方法:

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

    此处的返回值是id类型的,也就是数据解析完之后的数据。

    顺便提一下返回值解析的调用函数是在AFURLSessionManager中的网络请求成功的回调中:

    - (void)URLSession:(__unused NSURLSession *)session
                  task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wgnu"
        __strong AFURLSessionManager *manager = self.manager;
    
        __block id responseObject = nil;
    
        __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
        userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
    
        //Performance Improvement from #2672
        NSData *data = nil;
        if (self.mutableData) {
            data = [self.mutableData copy];
            //We no longer need the reference, so nil it out to gain back some memory.
            self.mutableData = nil;
        }
    
        if (self.downloadFileURL) {
            userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
        } else if (data) {
            userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
        }
    
        if (error) {
            userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
    
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, error);
                }
    
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        } else {
            dispatch_async(url_session_manager_processing_queue(), ^{
                NSError *serializationError = nil;
                responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]; // 此处进行数据的解析
    
                if (self.downloadFileURL) {
                    responseObject = self.downloadFileURL;
                }
    
                if (responseObject) {
                    userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
                }
    
                if (serializationError) {
                    userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
                }
    
                dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                    if (self.completionHandler) {
                        self.completionHandler(task.response, responseObject, serializationError);
                    }
    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                    });
                });
            });
        }
    #pragma clang diagnostic pop
    }
    

    下面看一下各个类不同职能分别的实现:
    父类AFHTTPResponseSerializer 中的实现:

    - (id)responseObjectForResponse:(NSURLResponse *)response
                               data:(NSData *)data
                              error:(NSError *__autoreleasing *)error
    {
        [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
    
        return data;
    }
    

    此处就一个方法,就是做了一个返回的数据是否有效。但是数据是否有错,都会返回原始数据,没有做任何的修改。
    看一下返回数据有效性的方法实现:

    - (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]) {
                    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;
    }
    

    这里主要做了判断是不是支持的返回content-type类型,再就是状态码是不是200+,如果不满足就不是有效的返回数据。
    看下初始化值:

    self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
    self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
    

    子类AFJSONResponseSerializer中的实现:

    - (id)responseObjectForResponse:(NSURLResponse *)response
                               data:(NSData *)data
                              error:(NSError *__autoreleasing *)error
    {
        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
        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;
        }
    
        if (self.removesKeysWithNullValues && responseObject) {
            responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
        }
    
        if (error) {
            *error = AFErrorWithUnderlyingError(serializationError, *error);
        }
    
        return responseObject;
    }
    

    此处看到在父类中对有效性的判断结果并没有做处理,而在Json转换类中,如果返回数据是无效的,直接就返回nil。然后就是对返回数据进行了Json转换。并对结果进行了空值进行了排空。

    其他的子类的封装思路也都相似,不再一一赘述。注意的是不同的功能的子类对返回值的类型支持是不同的。

    如果文中有什么错误,欢迎大家指正。

    更多问题讨论欢迎加QQ群:200792066

    转载请注明出处:http://semyonxu.com

    相关文章

      网友评论

        本文标题:AFNetworking 3.0 源码解析之Serializat

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