AFNetwork 3.0 源码解读(四)AFURLResponseSerialization

AFURLResponseSerialization相对于AFURLRequestSerialization,一个是网络请求的序列化,一个是网络响应的序列化。AFURLResponseSerialization是将网络请求回来的数据 解析 检查数据是否合法,把NSData数据转成相应的对象

在AFURLResponseSerialization类中包含了:
AFURLResponseSerialization协议
AFHTTPResponseSerializer
AFHTTPResponseSerializer的子类们
AFJSONResponseSerializer
AFXMLParserResponseSerializer
AFImageResponseSerializer

主要的检测方法:
/// 解析 response为对应的数据类型(JSON、XML、plist、Image)
- ( nullable id )responseObjectForResponse:( nullable NSURLResponse *)response
                           data:( nullable NSData *)data
                                   error:(NSError * _Nullable __autoreleasing *)error;

/// 使用此方法来检测当前的 response是否有限
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
                    data:(nullable NSData *)data
                   error:(NSError * _Nullable __autoreleasing *)error;

– responseObjectForResponse:data:error: 方法主要作用是对返回的数据进行解析,AFHTTPResponseSerializer的子类会重写这个方法,根据不同的需要解析成不同的结果,如AFJSONResponseSerializer会将数据解析成为JSON数据,

以AFJSONResponseSerializer的解析为例如下:

Data转JSON的顺序: data -> string -> data -> JSON
- (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;
        }
    }

    NSStringEncoding stringEncoding = self.stringEncoding;
   
if (response.textEncodingName) {
       
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
       
if (encoding != kCFStringEncodingInvalidId) {
            stringEncoding =
CFStringConvertEncodingToNSStringEncoding(encoding);
        }
    }

   
id responseObject = nil;
   
NSError *serializationError = nil;
    @autoreleasepool {
                    /// 根据自己设置的stringEncoding将data先转换成NSString
        NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding];
        if (responseString && ![responseString isEqualToString:@" "]) {
                         /// 再将string使用UTF8编码转换成Data
            data = [responseString dataUsingEncoding:NSUTF8StringEncoding];

           
if (data) {
                if ([data length] > 0) {
                                                  /// 有效的data数据,使用系统自带的 NSJSONSerialization 转换成JSON
                    responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
                }
else {
                   
return nil;
                }
            } else {
                /// 错误信息
                NSDictionary *userInfo = @{
                                          
NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Data failed decoding as a UTF-8 string", @"AFNetworking", nil),
                                          
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Could not decode string: %@", @"AFNetworking", nil), responseString]
                                          
};

                serializationError = [
NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
            }
        }
    }

   
if (self.removesKeysWithNullValues && responseObject) {
        responseObject =
AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
    }

   
if (error) {
        *error =
AFErrorWithUnderlyingError(serializationError, *error);
    }

   
return responseObject;
}
AFJSONResponseSerializer使用系统内置的NSJSONSerialization解析json,NSJSON只支持解析UTF8编码的数据(还有UTF-16LE之类的,都不常用),所以要先把返回的数据转成UTF8格式。这里会尝试用HTTP返回的编码类型和自己设置的stringEncoding去把数据解码转成字符串NSString,再把NSString用UTF8编码转成NSData,再用NSJSONSerialization解析成对象返回。

同时 AFJSONResponseSerializer会使用 AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions)方法;递归会将返回的数据中值为nil或者为NSNull的键移除。。


猜你喜欢

转载自blog.csdn.net/yuwuchaio/article/details/50457310