AFNetworking3.0源碼分析---學(xué)習(xí)

AFN2.0 和3.0的區(qū)別和改動(dòng)

AFN2.0:

1.對(duì)NSURLSession的封裝
2.對(duì)AFURLConnection的封裝
3.對(duì)HTTPS網(wǎng)絡(luò)安全請(qǐng)求做了一個(gè)包裝
4.做了一個(gè)網(wǎng)絡(luò)連接管理的一個(gè)包裝,

AFN3.0:

1>添加進(jìn)度回調(diào)
2> 去掉所有AFURLConnection

AF的5個(gè)功能模塊:

  • 網(wǎng)絡(luò)通信模塊(AFURLSessionManager、AFHTTPSessionManger)
  • 網(wǎng)絡(luò)狀態(tài)監(jiān)聽模塊(Reachability)
  • 網(wǎng)絡(luò)通信安全策略模塊(Security)
  • 網(wǎng)絡(luò)通信信息序列化/反序列化模塊(Serialization)
  • 對(duì)于iOS UIKit庫的擴(kuò)展(UIKit)

核心模塊:網(wǎng)絡(luò)通信模塊AFURLSessionManager

AF3.x是基于NSURLSession來封裝的。所以這個(gè)類圍繞著NSURLSession做了一系列的上層封裝。而其余的四個(gè)模塊,均是為了配合AFURLSessionManager類的網(wǎng)絡(luò)通信做一些必要的處理工作。結(jié)構(gòu)關(guān)系如下:

1703a3bca408bda0ed3c38b943dad7fd.jpg
其中AFHTTPSessionManager是繼承于AFURLSessionManager的

我們一般做網(wǎng)絡(luò)請(qǐng)求都是用這個(gè)類,但是它本身是沒有做實(shí)事的,只是做了一些簡(jiǎn)單的封裝,把請(qǐng)求邏輯分發(fā)給父類AFURLSessionManager去做。

一.其中AFHTTPSessionManager做的事情是:

1.創(chuàng)建管理對(duì)象,封裝對(duì)外接口
2.在GET和POST方法中,調(diào)用父類方法把從父類獲取到的task ,resume

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

3.把傳過來的參數(shù),編碼成我們請(qǐng)求時(shí)需要的request,并且傳給父類去做網(wǎng)絡(luò)請(qǐng)求
做這個(gè)事情的代碼如下:

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error
{
    //斷言,debug模式下,如果缺少改參數(shù),crash
    NSParameterAssert(method);
    NSParameterAssert(URLString);

    NSURL *url = [NSURL URLWithString:URLString];

    NSParameterAssert(url);

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

    //將request的各種屬性循環(huán)遍歷
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        //如果自己觀察到的發(fā)生變化的屬性,在這些方法里
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
           //把給自己設(shè)置的屬性給request設(shè)置
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }
    //將傳入的parameters進(jìn)行編碼,并添加到request中
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

    return mutableRequest;
}

在AFN中,每一個(gè)task都會(huì)被匹配一個(gè)AFURLSessionManagerTaskDelegate 來做task的delegate事件處理

二.AFURLSessionManager的初始化方法

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

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

    self.sessionConfiguration = configuration;

    self.operationQueue = [[NSOperationQueue alloc] init];
    //queue并發(fā)線程數(shù)為1,這個(gè)是代理回調(diào)的queue
    self.operationQueue.maxConcurrentOperationCount = 1;


    //注意代理,代理的繼承,實(shí)際上NSURLSession去判斷了,你實(shí)現(xiàn)了哪個(gè)方法會(huì)去調(diào)用,包括子代理的方法!
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];


    //各種響應(yīng)轉(zhuǎn)碼
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    //ssl證書,是驗(yàn)證證書,還是公鑰,還是不用
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif


    // 設(shè)置存儲(chǔ)NSURL task與AFURLSessionManagerTaskDelegate的詞典(重點(diǎn),在AFNet中,每一個(gè)task都會(huì)被匹配一個(gè)AFURLSessionManagerTaskDelegate 來做task的delegate事件處理) ===============
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    // =============== 設(shè)置AFURLSessionManagerTaskDelegate 詞典的鎖,確保詞典在多線程訪問時(shí)的線程安全===============
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    // =============== 為所管理的session的所有task設(shè)置完成塊,此方法為生成session之后就調(diào)用
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        //開始的時(shí)候應(yīng)該什么都沒有
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}

其中兩個(gè)方法比較重要:
1. self.operationQueue.maxConcurrentOperationCount = 1;

2. [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
       //置空處理
 }];

其作用為:

  • 第一是讓回調(diào)的代理queue是串行的,即請(qǐng)求完成的task只能一個(gè)個(gè)被回調(diào)。
  • 第二是清空了session中所有task。

其目的:
第一個(gè):

第二個(gè):我們知道這里是初始化方法,按理說session中不會(huì)有任何task。但是我們有一種后臺(tái)session,當(dāng)從后臺(tái)回來的時(shí)候,根據(jù)一個(gè)ID,就可以重新恢復(fù)這個(gè)session,這時(shí)候其中就會(huì)有之前未完成的task了。
所以:

而這里這么做的目的就是防止一些之前的后臺(tái)請(qǐng)求任務(wù),導(dǎo)致程序的crash

接著是dataTaskWithRequest方法:

- (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 {


    __block NSURLSessionDataTask *dataTask = nil;
    //第一件事,創(chuàng)建NSURLSessionDataTask,里面適配了Ios8以下taskIdentifiers,函數(shù)創(chuàng)建task對(duì)象。
    //其實(shí)現(xiàn)應(yīng)該是因?yàn)閕OS 8.0以下版本中會(huì)并發(fā)地創(chuàng)建多個(gè)task對(duì)象,而同步有沒有做好,導(dǎo)致taskIdentifiers 不唯一…這邊做了一個(gè)串行處理
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

這里所做的有兩件事:
1.調(diào)用session的方法,傳request過去去生成task。

  1. 給每個(gè)task創(chuàng)建并對(duì)應(yīng)一個(gè)AF的代理對(duì)象,這基本上是這個(gè)類的核心所在了,這個(gè)代理對(duì)象為其對(duì)應(yīng)的task做數(shù)據(jù)拼接及成功回調(diào)。
    正如上面所說,AFN中每一個(gè)task都會(huì)被對(duì)應(yīng)生成一個(gè)delegate并與之匹配,其所有核心方法都為代理調(diào)用
- (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] init];

    // AFURLSessionManagerTaskDelegate與AFURLSessionManager建立相互關(guān)系
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    //這個(gè)taskDescriptionForSessionTasks用來發(fā)送開始和掛起通知的時(shí)候會(huì)用到,就是用這個(gè)值來Post通知,來兩者對(duì)應(yīng)
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;

    // ***** 將AF delegate對(duì)象與 dataTask建立關(guān)系
    [self setDelegate:delegate forTask:dataTask];

    // 設(shè)置AF delegate的上傳進(jìn)度,下載進(jìn)度塊。
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    //斷言,如果沒有這個(gè)參數(shù),debug下crash在這
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    //加鎖保證字典線程安全
    [self.lock lock];

    // 將AF delegate放入以taskIdentifier標(biāo)記的詞典中(同一個(gè)NSURLSession中的taskIdentifier是唯一的)
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;

    // 為AF delegate 設(shè)置task 的progress監(jiān)聽
    [delegate setupProgressForTask:task];

    //添加task開始和暫停的通知
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

就這么兩個(gè)方法創(chuàng)建了一個(gè)AFURLSessionManagerTaskDelegate的代理,把這個(gè)代理和task的taskIdentifier一一對(duì)應(yīng),放在我們最早初始化(initWithSessionConfiguration方法中創(chuàng)建的mutableTaskDelegatesKeyedByTaskIdentifier)的字典里,建立起映射。
這里所做的還包括對(duì)task進(jìn)度的監(jiān)聽和掛起與重新開始的通知。
做完以上操作后,在AFHTTPSessionManager中調(diào)用resume方法

[dataTask resume];

其中主要的三個(gè)代理有:
1.完成的代理
2.收到數(shù)據(jù)的代理
3.以及下載完成的代理

AFN中還為每個(gè)代理方法,聲明了對(duì)應(yīng)的屬性Block,我們可以利用這些Block,做一些自定義的處理,Block會(huì)隨著代理調(diào)用而被調(diào)用,這些代理幫我們做了一些類似數(shù)據(jù)分片、斷電續(xù)傳、https認(rèn)證等工作

以其中一個(gè)為例:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{    
    //根據(jù)task去取我們一開始創(chuàng)建綁定的delegate
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // delegate may be nil when completing a task in the background
    if (delegate) {
        //把代理轉(zhuǎn)發(fā)給我們綁定的delegate
        [delegate URLSession:session task:task didCompleteWithError:error];
        //轉(zhuǎn)發(fā)完移除delegate
        [self removeDelegateForTask:task];
    }

    //公用Block回調(diào)
    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}

其中的代理調(diào)用的方法實(shí)現(xiàn)如下:

//AF實(shí)現(xiàn)的代理!被從urlsession那轉(zhuǎn)發(fā)到這

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"

    //1)強(qiáng)引用self.manager,防止被提前釋放;因?yàn)閟elf.manager聲明為weak,類似Block

    __strong AFURLSessionManager *manager = self.manager;

    __block id responseObject = nil;

    //用來存儲(chǔ)一些相關(guān)信息,來發(fā)送通知用的
    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    //存儲(chǔ)responseSerializer響應(yīng)解析對(duì)象
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

    //Performance Improvement from #2672

    //注意這行代碼的用法,感覺寫的很Nice...把請(qǐng)求到的數(shù)據(jù)data傳出去,然后就不要這個(gè)值了釋放內(nèi)存
    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;
    }

    //繼續(xù)給userinfo填數(shù)據(jù)
    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }
    //錯(cuò)誤處理
    if (error) {

        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;

        //可以自己自定義完成組 和自定義完成queue,完成回調(diào)
        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);
            }
            //主線程中發(fā)送完成通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {
        //url_session_manager_processing_queue AF的并行隊(duì)列
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;

            //解析數(shù)據(jù)
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];

            //如果是下載文件,那么responseObject為下載的路徑
            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }

            //寫入userInfo
            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }

            //如果解析錯(cuò)誤
            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }
            //回調(diào)結(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];
                });
            });
        });
    }
#pragma clang diagnostic pop
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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