AFNetworking3.x 源码解析

概述

  • AFNetworking3.x 其实是对 NSUrlSession 的封装;

  • AFNetworking 总共分为 5 个模块:

    1. 通信模块 AFHTTPSessionManager, AFURLSessionManager ;
    2. 网络检测模块 AFNetworkReachabilityManager ;
    3. 网络安全https模块 AFSecurityPolicy ;
    4. 序列化和反序列化模块 Serialization ;
    5. ui组件封装模块 ;
AFHTTPSessionManager *manage = [[AFHTTPSessionManager alloc] init];
    [manage GET:@"http://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

    }];

解析通信模块

  • AFHTTPSessionManagerAFURLSessionManager 子类,提供给外界使用的网路请求类;

  • AFHTTPSessionManager在初始化时, 设置了默认的序列对象为AFHTTPRequestSerializer,反序列化对象为AFJSONResponseSerializer,并且调用父类的初始化方法;

  • 在父类的初始化方法中,创建了一个队列,并发量为 1,是为了保证请求在回调时,串行执行,防止数据错落;但为何不设置并发量为n,然后回调时用NSLock来防止数据错乱问题呢?

使用NSLock来锁住、解锁,会增加等待加锁和解锁时间,并且开销额外的线程开支,所以使用并发量为1,解决这个问题;

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;

    // 定义一个并发量为1 的队列, 用来保证响应数据的回调是串行的,但是数据解析还是并发执行的
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    self.responseSerializer = [AFJSONResponseSerializer serializer];

    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

虽然请求的回调是串行回调,但是请求完成后的数据解析是并发解析的,后续会分析...

  • 进入AFHTTPSessionManager的GET 或 POST方法内部,可以看到内部是返回一个 NSURLSessionDataTask 对象,并且直接开始请求 resume
- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(id)parameters
                     progress:(void (^)(NSProgress * _Nonnull))downloadProgress
                      success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                      failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{

    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
                                                        URLString:URLString
                                                       parameters:parameters
                                                   uploadProgress:nil
                                                 downloadProgress:downloadProgress
                                                          success:success
                                                          failure:failure];

    [dataTask resume];

    return dataTask;
}
  • dataTaskWithHTTPMethod 方法首先会创建一个 NSMutableURLRequest 的对象, 并对传进来的参数进行合成,如get方法将参数放置于url,post将参数放置在请求体;其次会创建一个 NSURLSessionDataTask 对象,并返回;
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure

{
    // 1. 生成NSMutableURLRequest, 对参数进行合成
    NSError *serializationError = nil;

    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];

    if (serializationError) {
        if (failure) {

            // 有错误就返回自定义的队列回调, 如果没有自定的队列就主队列回调
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }

    // 2. 生成NSURLSessionDataTask任务对象, 并返回
    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];
    return dataTask;
}
  • 进入 requestWithMethod 看内部如何实现,可以看出在该方法中创建了 NSMutableURLRequest 对象,然后遍历 mutableObservedChangedKeyPaths 集合,该集合是存放了外界自定义的一些属性,比如超时时间等,然后根据外界传输的请求数据格式,调用不同的代理方法,生成不一样的Request对象;
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error
{
    NSParameterAssert(method);
    NSParameterAssert(URLString);

    NSURL *url = [NSURL URLWithString:URLString];

    NSParameterAssert(url);

    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    mutableRequest.HTTPMethod = method;

    // 将用户自定义的属性放到mutableRequest,比如超时时间,是否允许蜂窝网络请求等
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    // 生成NSMutableURLRequest,下面这个方法是代理方法,每个请求的数据格式不一样,所以看子类的继承 Content-Type , NSDate 会不一样
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

    return mutableRequest;
}
  • 介绍完如何NSMutableURLRequest的创建,来看看 NSURLSessionDataTask 的创建做了哪些事,进入dataTaskWithRequest方法内部;
    1. 可以看到首先创建了NSURLSessionDataTask对象,但是由于iOS8.0以下版本由于并发创建NSURLSessionDataTask会导致taskId不唯一,所以在iOS8.0以下,需要在 同步串行队列 中创建;
    2. 然后调用 addDelegateForDataTask 创建代理对象;
    3. 该代理对象主要作用是用来 解偶 AFURLSessionManager对象的,将回调数据解析等都放置到代理对象中;
    4. 可以看到manage = self ,是对应AFURLSessionManager对象的,然后将代理对象存放着在 mutableTaskDelegatesKeyedByTaskIdentifier 字典中,self.mutableTaskDelegatesKeyedByTaskIdentifier[@(taskIdentifier)] = delegate;
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {

    
    // 1. 安全创建NSURLSessionDataTask对象
    // 1.1 因为iOS8.0之前的系统,不能保证在并发线程中taskId唯一,所以用同步、串行队列进行创建
    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    // 2. 创建代理对象,用来处理请求完成回调
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
              downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
             completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}
  • 然后介绍请求回调,可以看到AFURLSessionManager中的请求回调,都是将数据转发给 AFURLSessionManagerTaskDelegate 代理,然后让这个代理进行回调给外界;
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{

    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    [delegate URLSession:session dataTask:dataTask didReceiveData:data];

    if (self.dataTaskDidReceiveData) {
        self.dataTaskDidReceiveData(session, dataTask, data);
    }
}
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    
    
    // 1. 请求完成后,回调到AFURLSessionManagerTaskDelegate中,进行数据处理后,将数据回调到最初的get回调(用户)
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // delegate may be nil when completing a task in the background
    if (delegate) {
        [delegate URLSession:session task:task didCompleteWithError:error];

        // 1.1 请求完成后,需要移除delegate
        [self removeDelegateForTask:task];
    }

    // 2. 用户自定义的回调
    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}
  • 转到 AFURLSessionManagerTaskDelegate 代理方法中,可以看到初始化了一个字典,存放解析的数据,回调有 block通知 两种;响应数据的解析放在 异步并发队列 中执行,然后以block和通知方式回调给外界使用,整个请求过程结束,然后移除delegate对象;
- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    // 1. 合成userInfo 的通知信息
    __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 {

        // 2. 并发解析数据
        dispatch_async(url_session_manager_processing_queue(), ^{

            // 3. 使用代理方法, 解析响应的数据
            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;
            }

            // 4. 回调给用户解析后的数据, 整个请求结束
            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];
                });
            });
        });
    }
}

上述只是通信模块的分析,其余模块后续补上。。。。。

你可能感兴趣的:(AFNetworking3.x 源码解析)