AFNetworking3.x 源碼解析

概述

  • AFNetworking3.x 其實(shí)是對 NSUrlSession 的封裝;

  • AFNetworking 總共分為 5 個(gè)模塊:

    1. 通信模塊 AFHTTPSessionManager, AFURLSessionManager ;
    2. 網(wǎng)絡(luò)檢測模塊 AFNetworkReachabilityManager ;
    3. 網(wǎng)絡(luò)安全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 子類,提供給外界使用的網(wǎng)路請求類;

  • AFHTTPSessionManager在初始化時(shí), 設(shè)置了默認(rèn)的序列對象為AFHTTPRequestSerializer,反序列化對象為AFJSONResponseSerializer,并且調(diào)用父類的初始化方法;

  • 在父類的初始化方法中,創(chuàng)建了一個(gè)隊(duì)列,并發(fā)量為 1,是為了保證請求在回調(diào)時(shí),串行執(zhí)行,防止數(shù)據(jù)錯(cuò)落;但為何不設(shè)置并發(fā)量為n,然后回調(diào)時(shí)用NSLock來防止數(shù)據(jù)錯(cuò)亂問題呢?

使用NSLock來鎖住、解鎖,會增加等待加鎖和解鎖時(shí)間,并且開銷額外的線程開支,所以使用并發(fā)量為1,解決這個(gè)問題;

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

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

    self.sessionConfiguration = configuration;

    // 定義一個(gè)并發(fā)量為1 的隊(duì)列, 用來保證響應(yīng)數(shù)據(jù)的回調(diào)是串行的,但是數(shù)據(jù)解析還是并發(fā)執(zhí)行的
    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];

雖然請求的回調(diào)是串行回調(diào),但是請求完成后的數(shù)據(jù)解析是并發(fā)解析的,后續(xù)會分析...

  • 進(jìn)入AFHTTPSessionManager的GET 或 POST方法內(nèi)部,可以看到內(nèi)部是返回一個(gè) 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 方法首先會創(chuàng)建一個(gè) NSMutableURLRequest 的對象, 并對傳進(jìn)來的參數(shù)進(jìn)行合成,如get方法將參數(shù)放置于url,post將參數(shù)放置在請求體;其次會創(chuàng)建一個(gè) 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, 對參數(shù)進(jìn)行合成
    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) {

            // 有錯(cuò)誤就返回自定義的隊(duì)列回調(diào), 如果沒有自定的隊(duì)列就主隊(duì)列回調(diào)
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }

    // 2. 生成NSURLSessionDataTask任務(wù)對象, 并返回
    __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;
}
  • 進(jìn)入 requestWithMethod 看內(nèi)部如何實(shí)現(xiàn),可以看出在該方法中創(chuàng)建了 NSMutableURLRequest 對象,然后遍歷 mutableObservedChangedKeyPaths 集合,該集合是存放了外界自定義的一些屬性,比如超時(shí)時(shí)間等,然后根據(jù)外界傳輸?shù)恼埱髷?shù)據(jù)格式,調(diào)用不同的代理方法,生成不一樣的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,比如超時(shí)時(shí)間,是否允許蜂窩網(wǎng)絡(luò)請求等
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    // 生成NSMutableURLRequest,下面這個(gè)方法是代理方法,每個(gè)請求的數(shù)據(jù)格式不一樣,所以看子類的繼承 Content-Type , NSDate 會不一樣
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

    return mutableRequest;
}
  • 介紹完如何NSMutableURLRequest的創(chuàng)建,來看看 NSURLSessionDataTask 的創(chuàng)建做了哪些事,進(jìn)入dataTaskWithRequest方法內(nèi)部;
    1. 可以看到首先創(chuàng)建了NSURLSessionDataTask對象,但是由于iOS8.0以下版本由于并發(fā)創(chuàng)建NSURLSessionDataTask會導(dǎo)致taskId不唯一,所以在iOS8.0以下,需要在 同步串行隊(duì)列 中創(chuàng)建;
    2. 然后調(diào)用 addDelegateForDataTask 創(chuàng)建代理對象;
    3. 該代理對象主要作用是用來 解偶 AFURLSessionManager對象的,將回調(diào),數(shù)據(jù)解析等都放置到代理對象中;
    4. 可以看到manage = self ,是對應(yīng)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. 安全創(chuàng)建NSURLSessionDataTask對象
    // 1.1 因?yàn)閕OS8.0之前的系統(tǒng),不能保證在并發(fā)線程中taskId唯一,所以用同步、串行隊(duì)列進(jìn)行創(chuàng)建
    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    // 2. 創(chuàng)建代理對象,用來處理請求完成回調(diào)
    [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;
}
  • 然后介紹請求回調(diào),可以看到AFURLSessionManager中的請求回調(diào),都是將數(shù)據(jù)轉(zhuǎn)發(fā)給 AFURLSessionManagerTaskDelegate 代理,然后讓這個(gè)代理進(jìn)行回調(diào)給外界;
- (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. 請求完成后,回調(diào)到AFURLSessionManagerTaskDelegate中,進(jìn)行數(shù)據(jù)處理后,將數(shù)據(jù)回調(diào)到最初的get回調(diào)(用戶)
    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. 用戶自定義的回調(diào)
    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}
  • 轉(zhuǎn)到 AFURLSessionManagerTaskDelegate 代理方法中,可以看到初始化了一個(gè)字典,存放解析的數(shù)據(jù),回調(diào)有 block通知 兩種;響應(yīng)數(shù)據(jù)的解析放在 異步并發(fā)隊(duì)列 中執(zhí)行,然后以block和通知方式回調(diào)給外界使用,整個(gè)請求過程結(jié)束,然后移除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. 并發(fā)解析數(shù)據(jù)
        dispatch_async(url_session_manager_processing_queue(), ^{

            // 3. 使用代理方法, 解析響應(yīng)的數(shù)據(jù)
            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. 回調(diào)給用戶解析后的數(shù)據(jù), 整個(gè)請求結(jié)束
            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];
                });
            });
        });
    }
}

上述只是通信模塊的分析,其余模塊后續(xù)補(bǔ)上。。。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 《貨幣的教訓(xùn):匯率與貨幣系列評論》——作者:周其仁 自己是個(gè)好奇心較強(qiáng)的人,對陌生的知識總?cè)滩蛔∠攵嗔私庑绕涫?..
    吳蜀魏閱讀 650評論 0 0
  • 今天晚上,媽媽做的炸鮮奶。昨天晚上的時(shí)候姐姐要吃炸鮮奶,媽媽昨天做的鮮奶條。使用純牛奶加上白糖,再加上淀粉。然后放...
    張賀辰閱讀 210評論 0 3
  • 有一種無言,那便是我懂你的愛,而你卻不懂我的情。
    紫嫣sophia閱讀 567評論 8 14
  • 治病以來記憶一直模模糊糊,日記本換過好多次,始終記錄不了生活。有時(shí)候談?wù)撈疬^去,我腦子里的,不是錯(cuò)誤的記憶...
    小白DSY閱讀 86評論 0 0

友情鏈接更多精彩內(nèi)容