AFNetworking 3.0 源碼閱讀筆記(二)

原文鏈接:http://itangqi.me/2016/05/06/the-notes-of-learning-afnetworking-two/

前言

首先,我們來看一下 AFNetworking 框架中主要涉及到了哪些類:

NSURLSession

  • AFURLSessionManager
  • AFHTTPSessionManager

序列化

  • AFURLRequestSerialization
  • AFURLResponseSerialization

附加功能

  • AFSecurityPolicy
  • AFNetworkReachabilityManager

下面,通過一張圖來直觀地感受下 AF 架構的設計:


AFHTTPSessionManager

AFHTTPSessionManager is a subclass of AFURLSessionManager with convenience methods for making HTTP requests. When a baseURL is provided, requests made with the GET / POST / et al. convenience methods can be made with relative paths.

一句話總結:AFHTTPSessionManager 繼承於 AFURLSessionManager,並提供了方便的 HTTP 請求方法。

下面,我們通過一段實際代碼來感受下:

1
2
3
4
5
6
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.app.net/"]];
[sessionManager GET:@"stream/0/posts/stream/global" parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
    NSLog(@"請求成功---%@", responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"請求失敗---%@", error);
}];

通過上面短短几行代碼,我們便完成了 GET 請求,有木有很簡單!現在是不是很想知道其背後蘊藏的玄機呢?別急,下面就讓我們一起來探一探究竟。


調用棧

initWithBaseURL:

首先,我們來探一探 AFHTTPSessionManager 初始化方法 - initWithBaseURL: 的調用棧:

1
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.app.net/"]];

我們一路「Command + 左鍵」,可以歸納出如下結果:

1
2
3
4
5
6
7
8
9
- [AFHTTPSessionManager initWithBaseURL:]
    - [AFHTTPSessionManager initWithBaseURL:sessionConfiguration:]
        - [AFURLSessionManager initWithSessionConfiguration:]
            - [NSURLSession sessionWithConfiguration:delegate:delegateQueue:]
            - [AFJSONResponseSerializer serializer] // 負責序列化響應
            - [AFSecurityPolicy defaultPolicy] // 負責身份認證
            - [AFNetworkReachabilityManager sharedManager] // 查看網絡連接情況
        - [AFHTTPRequestSerializer serializer] // 負責序列化請求
        - [AFJSONResponseSerializer serializer] // 負責序列化響應

從這個初始化方法的調用棧,我們可以非常清晰地瞭解這個框架的結構:

  • 其中 AFURLSessionManagerAFHTTPSessionManager 的父類
  • AFURLSessionManager 負責生成 NSURLSession 的實例,管理 AFSecurityPolicyAFNetworkReachabilityManager,來保證請求的安全和查看網絡連接情況,它有一個 AFJSONResponseSerializer 的實例來序列化 HTTP 響應
  • AFHTTPSessionManager 有着自己的 AFHTTPRequestSerializerAFJSONResponseSerializer 來管理請求和響應的序列化,同時依賴父類提供的接口保證安全、監控網絡狀態,實現發出 HTTP 請求這一核心功能

baseURL

關於 baseURL 一開始我是有點迷糊的,不過源代碼中有如下注釋:

For HTTP convenience methods, the request serializer constructs URLs from the path relative to the -baseURL, using NSURL +URLWithString:relativeToURL:, when provided. If baseURL is nil, path needs to resolve to a valid NSURL object using NSURL +URLWithString:.

並舉例進行了說明:

1
2
3
4
5
6
7
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL];                  // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL];          // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL];                 // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL];                 // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL];                // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/

所以,baseURL 爲訪問的基路徑如:https://api.app.net/, path 是跟在基路徑之後的部分路徑,如:stream/0/posts/stream/global(因爲 AFNetworking 的訪問方式才這樣劃分)。

GET:parameters:process:success:failure:

初始化方法很好地揭示了 AFNetworking 整個框架的架構,接下來我們要通過分析另一個方法 - GET:parameters:process:success:failure: 的調用棧,看一下 HTTP 請求是如何發出的:

1
2
3
4
5
6
7
8
9
- [AFHTTPSessionManager GET:parameters:process:success:failure:]
    - [AFHTTPSessionManager dataTaskWithHTTPMethod:parameters:uploadProgress:downloadProgress:success:failure:] // 返回 NSURLSessionDataTask #1
        - [AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:] // 返回 NSMutableURLRequest
        - [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] // 返回 NSURLSessionDataTask #2
            - [NSURLSession dataTaskWithRequest:] // 返回 NSURLSessionDataTask #3
            - [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:]
                - [AFURLSessionManagerTaskDelegate init]
                - [AFURLSessionManager setDelegate:forTask:]
    - [NSURLSessionDataTask resume]

在這裏 #1 #2 #3 處返回的是同一個 data task,我們可以看到,在 #3 處調用的方法 - [NSURLSession dataTaskWithRequest:] 和只使用 NSURLSession 發出 HTTP 請求時調用的方法 - [NSURLSession dataTaskWithRequest:completionHandler:] 差不多。在這個地方返回 data task 之後,我們再調用 - resume 方法執行請求,並在某些事件執行時通知代理 AFURLSessionManagerTaskDelegate

我們在第一篇文章中已經說明過,AFNetworking 3.0 既是在 NSURLSession 之上的高度封裝,並提供更加簡潔易用的 API。從調用棧的結果來看,將使我們的理解更加清晰。


循環引用

關於在使用 AFNetworking 的過程中出現循環引用的問題,我並沒有在實際開發中遇到過(其實我丫的根本就沒寫過幾行代碼好嘛( TДT)),我是在瀏覽相關文章時發現這個問題的,所以在此提及一下:


參考

發佈了24 篇原創文章 · 獲贊 19 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章