AFNetworking4.0框架源碼解讀

AFNetworking

一、簡介

AFNetworking 是對iOS中網(wǎng)絡(luò)請求方式 NSURLSession 的封裝,之前有NSURLConnection,后面已經(jīng)被廢棄。

在分析AFNetworking之前先來介紹一下使用 NSURLSession 發(fā)起一次網(wǎng)絡(luò)請求的步驟:

  1. 創(chuàng)建NSURLSessionCoftig對象
  2. 創(chuàng)建NSURLSession對象
  3. 創(chuàng)建task
  4. 調(diào)用resume開始執(zhí)行請求
  5. 代理響應(yīng)網(wǎng)絡(luò)事件及數(shù)據(jù)

二、框架結(jié)構(gòu)

這里分析4.0版本的結(jié)構(gòu)。主要分為五個部分:

1、NSURLSession:網(wǎng)絡(luò)通信模塊,兩個文件AFURLSessionManager,AFHTTPSessionManager。AFHTTPSessionManager繼承與AFURLSessionManager

2、Reachability 網(wǎng)絡(luò)狀態(tài)監(jiān)聽,AFNetworkReachabilityManager

3、Security 網(wǎng)絡(luò)通訊安全策略模塊,AFSecurityPolicy

4、Serialization 序列化,AFURLResponseSerialization,AFURLRequestSerialization

5、UIKit 對于UIKit的擴展庫

三、AFHTTPSessionManager 對象初始化過程,中間做了哪些事情

首先來看初始化AFHTTPSessionManager對象的過程,其中需要注意的是[AFHTTPSessionManager manager]方法并不是單例,調(diào)用的也是下面的方法返回。在AFHTTPSessionManager中主要做了 1、調(diào)用父類初始化方法,2、給URL加'/', 3、給requestSerializer、responseSerializer設(shè)置默認值

給url加'/'的目的應(yīng)該是1、防重發(fā) 2、方便在url后面拼接參數(shù)。如get請求方式


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

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}

下面來看AFURLSessionManager初始化方法。這里就不貼代碼了,需要的自己打開AF4.0源碼看吧。主要步驟有:

  1. sessionConfiguration 屬性持有 configuration ,若傳入configuration為空,設(shè)置默認defaultSessionConfiguration。包含緩存策略,ID,超時時間 ...
  2. 初始化代理方法執(zhí)行的隊列operationQueue,并設(shè)置 maxConcurrentOperationCount 值為1。即串行執(zhí)行
  3. responseSerializer 解析方式,
  4. securityPolicy 使用defaultPolicy初始化,https證書校驗對象,用來校驗服務(wù)端安全信任鏈接
  5. reachabilityManager 網(wǎng)絡(luò)狀態(tài)監(jiān)聽。
  6. mutableTaskDelegatesKeyedByTaskIdentifier 類型是NSMutableDictionary,key是NSURLSessionTask的唯一NSUInteger類型標(biāo)識,value是對應(yīng)的AFURLSessionManagerTaskDelgate對象
  7. lock ,NSLock類型鎖創(chuàng)建,為了保證線程安全
  8. session對象創(chuàng)建,3.0版本是直接創(chuàng)建。4.0版本是懶加載形式創(chuàng)建,并使用@synchronized互斥鎖保證只創(chuàng)建一次
  9. session 調(diào)用getTasksWithCompletionHandler方法獲取 之前的task,創(chuàng)建AFURLSessionManagerTaskDelegate。綁定task,并加入mutableTaskDelegatesKeyedByTaskIdentifier字典中

manager的研究先到這里,里面各種配置的具體實現(xiàn),暫時先不往深處介紹了,下面來看下request的實現(xiàn)方法

request方法解析


- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(nullable id)parameters
                                         headers:(nullable NSDictionary <NSString *, NSString *> *)headers
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                         failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    for (NSString *headerField in headers.keyEnumerator) {
        [request setValue:headers[headerField] forHTTPHeaderField:headerField];
    }
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

        return nil;
    }

    __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;
}

1、這個過程主要是使用requestSerializer 調(diào)用requestWithMethod 或者 multipartFormRequestWithMethod 獲取
NSMutableURLRequest 類型的 request 對象。

使用指定的HTTP method和URLString來構(gòu)建一個NSMutableURLRequest對象實例,如果method是GET、HEAD、DELETE,那parameter將會被用來構(gòu)建一個基于url編碼的查詢字符串(query url),并且這個字符串會直接加到request的url后面。對于其他的Method,比如POST/PUT,它們會根據(jù)parameterEncoding屬性進行編碼,而后加到request的http body上。


- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error 

在上面這個方法里設(shè)置了request的 請求方法,url,遍歷mutableObservedChangedKeyPaths中設(shè)置的屬性并給Request賦值,這里居然用了KVO。之前版本要遍歷AFHTTPRequestSerializerObservedKeyPaths()?,F(xiàn)在版本直接遍歷mutableObservedChangedKeyPaths,一大進步,之前就感覺這個設(shè)置很奇怪,終于修改了。

調(diào)用[mutableRequest setValue:value forHTTPHeaderField:field]方法設(shè)置請求頭相關(guān)信息。

非HTTPMethodsEncodingParametersInURI的請求先判斷request的Content-Type是否設(shè)置了,如果沒有,就默認設(shè)置為application/x-www-form-urlencoded。

在方法 multipartFormRequestWithMethod 中比 requestWithMethod 多了個參數(shù)為formData 的 block 對象參數(shù)。在方法體里面對formData 進行拼接。然后通過block傳出去。此處設(shè)計與Masonry框架中block使用方式相同,可以放一塊研究一下。

2、調(diào)用 dataTaskWithRequest 方法,使用上面的 request 生成 task 對象。


NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];

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

我要是沒記錯的話,3.0版本的時候在這里是用一個串行隊列創(chuàng)建dataTask,現(xiàn)在串行隊列相關(guān)代碼找不到了。用串行隊列來解決iOS8 的一個bug,可能現(xiàn)在已經(jīng)不用適配iOS8吧

addDelegateForDataTask 方法將初始化一個 AFURLSessionManagerTaskDelegate 對象,delegate 弱引用又持有了 manager, 打破閉環(huán)。在delegate中有 進度,回調(diào),存儲數(shù)據(jù)的mutableDate等屬性。

在addDelegateForDataTask 中調(diào)用 setDelegate:forTask 將task 和 delegate 綁定到一起。

在setDelegate:forTask 方法中 1、將delegate存入字典,以taskid作為key,說明每個task都有各自的代理; 2、設(shè)置兩個NSProgress的變量 - uploadProgress和downloadProgress,給session task添加了兩個KVO事件

設(shè)置這兩個NSProgress對應(yīng)的cancel、pause和resume這三個狀態(tài),正好對應(yīng)session task的cancel、suspend和resume三個狀態(tài)

當(dāng)NSURLSessionTask調(diào)用resume函數(shù)時,會postNotificationName:AFNSURLSessionTaskDidResumeNotification,從而執(zhí)行taskDidResume:方法

在 taskDidResume: 方法中會判斷task是否是當(dāng)前manager管理的,是的話會發(fā)送通知AFNetworkingTaskDidResumeNotification

3、task調(diào)用resume 執(zhí)行

resume 方法被 使用 method_exchangeImplementations交換為 af_resume方法。內(nèi)部發(fā)送了AFNSURLSessionTaskDidResumeNotification 通知。

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

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

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