【AFNetworking 分析】AFURLResponseSerialization

你。 提交于 2021-02-08 23:01:22

Pre

  • AFNetworking分析版本:4.0.1

结构图

  • 所有ResponseSerializer都实现了AFURLResponseSerialization协议
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
  • 序列化类父类AFHTTPResponseSerializer
@interface AFHTTPResponseSerializer : NSObject <AFURLResponseSerialization>
- (instancetype)init;
+ (instancetype)serializer;
@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
                    data:(nullable NSData *)data
                   error:(NSError * _Nullable __autoreleasing *)error;

@end
  • AFJSONResponseSerializer,AFXMLParseResponseSerializer等类都继承自AFHTTPResponseSerializer,由于AF中的HTTP请求的reponseSerializer默认为AFJSONResponseSerializer,我们再来看一下AFJSONResponseSerializer的接口
@interface AFJSONResponseSerializer : AFHTTPResponseSerializer
- (instancetype)init;
@property (nonatomic, assign) NSJSONReadingOptions readingOptions;
@property (nonatomic, assign) BOOL removesKeysWithNullValues;
+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions;
@end

在其初始化方法中,设置了可接受的content type为"application/json", "text/json","text/javascript"

调用流程

  • 入口:在之前文章中分析的封装请求过程中,会为当前的task对象添加一个AFURLSessionManagerTaskDelegate代理,它实现了NSURLSessionTaskDelegate协议,并实现了以下方法。也就是说我们收到的response会来到AFURLSessionManager的这个方法中。
- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error;

断点也可以证明确实走到了这里。

  1. 根据当前task获取到对应的delegate
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

/* delegateForTask:实现
 * 用之前分析过的task的identifier获取
 */
delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
  1. delegate不为空(若task在后台完成,delegate可能为空
  • 2.1 调用delegateURLSession: task:didCompleteWithError:方法
 [delegate URLSession:session task:task didCompleteWithError:error];
  • 2.2 移除该taskdelegatenotification
  1. 若当前manager设置过taskDidComplete,调用该block
if (self.taskDidComplete) {
    self.taskDidComplete(session, task, error);
}

delegate处理详解

  • 断点可以看到,走到时,该delegate类型为AFURLSessionManagerTaskDelegate 我们来进入该delegate的URLSession: task:didCompleteWithError:方法看看

获取部分数据存入字典userInfo

  • 该字典是一个局部变量,名为userInfo,可能有的key值为
  1. AuthenticationChallengeErrorKey为key获取task关联对象error,若为空则error仍为传进来的上层error(对不起这边还不太懂)
error = objc_getAssociatedObject(task, AuthenticationChallengeErrorKey) ?: error;
  1. 强引用获取manager,因为在delegate中对manager是弱引用,防止其被提前释放
  2. 若本delegate的mutableData不为空,获取一份copy值data将原属性值释放(因为再也用不着了)
    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;
    }

ps.self.mutableData数据来自于NSURLSessionDataTaskDelegate如下的回调方法接收获得:

- (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data{
    [self.mutableData appendData:data];
}
  1. 将本delegate的sessionTaskMetrics(若不为空)存入字典
  2. downloadFileURLdata(若不为空)存入字典

若出现error

  1. AFNetworkingTaskDidCompleteErrorKey为key将error存入字典
  2. 判断是否指定过本managercompletionGroupcompletionQueue,若有则使用,若无则使用创建的一个url_session_manager_completion_group调度组/主队列执行:
    2.1 异步调用completionHandler:block处理responseerror
    2.2 主队列上异步(避免阻塞主队列的其他任务执行)发送AFNetworkingTaskDidCompleteNotification通知(可以进行UI相关处理)

若无error(获取到正常的response)

  • 创建一个并发队列并执行
  1. 调用本managerresponseSerializer对接收到的taskresponse进行有效性验证。
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
  1. self.downloadFileURL不为空,赋值给responseObject
  • 什么情况不为空
  1. 若序列化后的responseObject不为空,存入字典
  2. 若序列化出错,将error传入字典
  3. 同【若出现error 第2步】

responseSerializer详解

  • 根据文首的结构图我们可以看到,responseSerializer可能为AFHTTPResponseSerializer(父),也可能为AFJSONResponseSerializer(子),AFXMLParserResponseSerializer(子)等类型。若调用者未设置,默认为AFJSONResponseSerializer类型,此处分析AFHTTPResponseSerializerAFJSONResponseSerializer对response的序列化解析流程,即responseObjectForResponse:data:error:方法。

AFHTTPResponseSerializer

  • 验证response的有效性,返回data(即上层的responseObject)和error
  • 此处解析AFHTTPResponseSerializervalidateResponse:data:error:方法
  1. 若返回内容类型无效/无法解析
    • acceptableContentTypes不不包含responseMIMEType
    • 封装错误类型(AFURLResponseSerializationErrorDomain
NSMutableDictionary *mutableUserInfo = [@{
                   NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
                   NSURLErrorFailingURLErrorKey:[response URL],
                   AFNetworkingOperationFailingURLResponseErrorKey: response,
                        } mutableCopy];
  1. 若返回的状态码无效
    • acceptableStatusCodes不包含response的状态码
    • 封装错误类型(AFURLResponseSerializationErrorDomain
NSMutableDictionary *mutableUserInfo = [@{
                    NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
                    NSURLErrorFailingURLErrorKey:[response URL],
                    AFNetworkingOperationFailingURLResponseErrorKey: response,
                      } mutableCopy];

AFJSONResponseSerializer

  1. 调用父类AFHTTPResponseSerializervalidateResponse:data:error:方法对返回内容有效性进行判断,若无效则返回nil
  2. 排除是否为一个空格(一个safari的bug)或为空的数据
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
  1. 调用NSJSONSerializationJSONObjectWithData方法解析data
  2. self.removesKeysWithNullValues属性值设置为YES (默认为NO),移除解析后的responseObject(JSON)中的空值
if (self.removesKeysWithNullValues) {
    return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}

a. 若responseObjectNSArray类型
- 创建可变数组
- 递归遍历responseObject向数组中添加元素
- 返回数组
b. 若responseObjectNSDictionary类型
- 用responseObject创建可变字典
- 遍历responseObject中所有key值
- 若value为空,移除;若为数组,递归;若为字典;递归
- 返回字典

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!