原文鏈接: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 ofAFURLSessionManager
with convenience methods for making HTTP requests. When abaseURL
is provided, requests made with theGET
/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] // 負責序列化響應 |
從這個初始化方法的調用棧,我們可以非常清晰地瞭解這個框架的結構:
- 其中
AFURLSessionManager
是AFHTTPSessionManager
的父類 AFURLSessionManager
負責生成NSURLSession
的實例,管理AFSecurityPolicy
和AFNetworkReachabilityManager
,來保證請求的安全和查看網絡連接情況,它有一個AFJSONResponseSerializer
的實例來序列化 HTTP 響應AFHTTPSessionManager
有着自己的AFHTTPRequestSerializer
和AFJSONResponseSerializer
來管理請求和響應的序列化,同時依賴父類提供的接口保證安全、監控網絡狀態,實現發出 HTTP 請求這一核心功能
baseURL
關於 baseURL
一開始我是有點迷糊的,不過源代碼中有如下注釋:
For HTTP convenience methods, the request serializer constructs URLs from the path relative to the
-baseURL
, usingNSURL +URLWithString:relativeToURL:
, when provided. IfbaseURL
isnil
,path
needs to resolve to a validNSURL
object usingNSURL +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)),我是在瀏覽相關文章時發現這個問題的,所以在此提及一下:
- AFHTTPSessionManager subclass not deallocating - retain cycle?
- AFHTTPSessionManager and AFURLSessionManager never deallocated
- block retain cycle in AFUrLSessionManager init method