/// Reference to `Session.default` for quick bootstrapping and examples.
public let AF = Session.default
/// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
let version = "5.4.0"
複製代碼
就這兩個常量, 一個是Session類的一個單例, 一個標記了當前版本號.bootstrap
/// 一個默認的單例
public static let `default` = Session()
/// 持有一個URLSession, 用來建立請求Task, 注意不能跟本對象持有的URLSessionTask產生交互, 不然會影響Alamofire內部邏輯
public let session: URLSession
/// 處理URLSession代理, URLSessionTaskDelegate, 以及請求攔截等邏輯
public let delegate: SessionDelegate
/// 內部回調執行以及狀態更新的隊列,必須是串行隊列
public let rootQueue: DispatchQueue
/// 是否在Request建立的時候就馬上發送, 該屬性用來統一管理Request建立時的startImmediately參數, 默認true
public let startRequestsImmediately: Bool
/// 異步建立Request的隊列,默認是rootQueue
public let requestQueue: DispatchQueue
/// 解析response的隊列, 默認是rootQueue
public let serializationQueue: DispatchQueue
/// 請求攔截器接口,是RequestAdapter跟RequestRetrier的結合, 默認nil
public let interceptor: RequestInterceptor?
/// 證書信任器接口, 默認nil
public let serverTrustManager: ServerTrustManager?
/// 重定向處理器接口, 默認nil
public let redirectHandler: RedirectHandler?
/// 緩存管理接口, 默認nil
public let cachedResponseHandler: CachedResponseHandler?
/// 事件監測管理器類,處理請求生命週期各階段的事件, 默認用下面的defaultEventMonitors以及傳入的事件檢測器初始化
public let eventMonitor: CompositeEventMonitor
/// 默認的事件監測器接口列表,只有一個通知事件監測器
public let defaultEventMonitors: [EventMonitor] = [AlamofireNotifications()]
/// 結構體, 用來保存Request跟URLSessiontask映射關係, 提供了各類方法來存取task跟request以及數量判斷, 爲空判斷
var requestTaskMap = RequestTaskMap()
/// 當前正在請求的Request集合
var activeRequests: Set<Request> = []
/// 等待成功的回調
var waitingCompletions: [URLSessionTask: () -> Void] = [:]
複製代碼
Session有兩個初始化方法, 一個必要初始化方法, 一個便捷初始化方法.swift
public init(session: URLSession, delegate: SessionDelegate, rootQueue: DispatchQueue, startRequestsImmediately: Bool = true, requestQueue: DispatchQueue? = nil, serializationQueue: DispatchQueue? = nil, interceptor: RequestInterceptor? = nil, serverTrustManager: ServerTrustManager? = nil, redirectHandler: RedirectHandler? = nil, cachedResponseHandler: CachedResponseHandler? = nil, eventMonitors: [EventMonitor] = []) {
// Alamofire不支持後臺下載(爲啥嘞?看後面是支持的)
precondition(session.configuration.identifier == nil,
"Alamofire does not support background URLSessionConfigurations.")
// URLSession的Queue跟rootQueue必須同樣
precondition(session.delegateQueue.underlyingQueue === rootQueue,
"Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")
self.session = session
self.delegate = delegate
self.rootQueue = rootQueue
self.startRequestsImmediately = startRequestsImmediately
// 默認用rootQueue作target建立請求響應解析隊列
self.requestQueue = requestQueue ?? DispatchQueue(label: "\(rootQueue.label).requestQueue", target: rootQueue)
self.serializationQueue = serializationQueue ?? DispatchQueue(label: "\(rootQueue.label).serializationQueue", target: rootQueue)
// 四個默認nil的屬性
self.interceptor = interceptor
self.serverTrustManager = serverTrustManager
self.redirectHandler = redirectHandler
self.cachedResponseHandler = cachedResponseHandler
// 根據傳入的事件監聽器以及默認的監聽器初始化CompositeEventMonitor對象
eventMonitor = CompositeEventMonitor(monitors: defaultEventMonitors + eventMonitors)
// 把組合監聽器對象丟給SessionDelegate對象用來管理task
delegate.eventMonitor = eventMonitor
// 請求時Session變化的處理
delegate.stateProvider = self
}
複製代碼
便捷初始化方法使用了默認的URLSessionConfiguration以及請求隊列來初始化URLSession, SessionDelegate, rootQueueapi
deinit {
finishRequestsForDeinit()
session.invalidateAndCancel()
}
func finishRequestsForDeinit() {
//挨個通知還沒完成的Request 返回sessionDeinitialized錯誤
requestTaskMap.requests.forEach { request in
rootQueue.async {
request.finish(error: AFError.sessionDeinitialized)
}
}
}
複製代碼
//對全部正在執行的請求執行一個閉包
public func withAllRequests(perform action: @escaping (Set<Request>) -> Void) {
rootQueue.async {
action(self.activeRequests)
}
}
//取消所有請求
public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) {
withAllRequests { requests in
requests.forEach { $0.cancel() }
queue.async {
completion?()
}
}
}
複製代碼
先定義了RequestConvertible與RequestEncodableConvertible結構體實現URLRequestConvertible協議, 用來使用不一樣參數建立URLRequestConvertible對象緩存
// 用來變換URLRequest對象的閉包
public typealias RequestModifier = (inout URLRequest) throws -> Void
//普通的request轉換器, 使用ParameterEncoding協議對象來編碼參數
struct RequestConvertible: URLRequestConvertible {
let url: URLConvertible//url
let method: HTTPMethod//方法
let parameters: Parameters?//參數
let encoding: ParameterEncoding//參數編碼對象, 默認URL編碼
let headers: HTTPHeaders?//請求頭
let requestModifier: RequestModifier?
}
//參數符合Encodable協議的轉換器, 使用ParameterEncoder協議對象編碼參數
struct RequestEncodableConvertible<Parameters: Encodable>: URLRequestConvertible {
let url: URLConvertible
let method: HTTPMethod
let parameters: Parameters?
let encoder: ParameterEncoder
let headers: HTTPHeaders?
let requestModifier: RequestModifier?
}
複製代碼
對於普通request, streamRequest, downloadRequest, 都有三個建立請求的方法:sass
- 先使用參數建立RequestConvertible對象, 而後轉換爲URLRequestConvertible後使用3來建立對應的Request對象
- 使用RequestConvertible建立, 邏輯同1
- 使用URLRequestConvertible對象+rootQueue+serializationQueue+eventMonitor建立Request對象, 並指定RequestDelegate爲self用來處理URLSessionConfiguration, 清理工做以及重試邏輯
- downloadRequest有一個額外的斷點續傳的方法, 使用已下載的Data來初始化DownloadRequest對象
對於UploadRequest, 又定義了ParameterlessRequestConvertible結構體實現URLRequestConvertible協議, 特色是沒有參數.
接着定義Upload結構體實現UploadConvertible用來封裝request與uploadable
對於UploadRequest的建立使用的都是ParameterlessRequestConvertible對象, 有共計X個建立UploadRequest的方法:安全
- 使用data + 請求基礎參數, 先生成ParameterlessRequestConvertible對象,轉2
- 使用data, URLRequestConvertible對象, 生成Uploadable.data對象, 轉11
- 使用fileURL + 請求基礎參數, 先生成ParameterlessRequestConvertible對象, 轉4
- 使用fileURL, ParameterlessRequestConvertible對象, 生成Uploadable.file對象, 轉11
- 使用InputStream + 基礎參數 轉6
- 使用InputStream, ParameterlessRequestConvertible, 生成Uploadable.stream對象,轉11
- 使用多表單閉包+請求基礎參數, 執行閉包生成MultipartFormData, ParameterlessRequestConvertible, 轉換爲URLRequestConvertible, 轉10
- 使用多表單閉包+URLRequestConvertible, 執行閉包, 轉10
- 使用MultipartFormData對象+基礎請求參數, 生成ParameterlessRequestConvertible, MultipartUpload, 轉12
- 使用MultipartFormData對象+URLRequestConvertible生成MultipartUpload, 轉12
- 如下爲intenal api, 外部沒法訪問
- 使用Uploadable + URLRequestConvertible, 生成Upload, 轉12 (在Session中未用到)
- 使用UploadConvertible協議對象生成UploadRequest併發送
注意:
- upload方法共有12個, 本質上upload方法分爲3種: data(內存), fileURL(磁盤), InputStream(磁盤), 7-10均爲處理多表單數據, 參數中帶有一個encodingMemoryThreshold參數, 用來決定編碼內存限制, 當表單數據大小大於該限制時, 編碼將把表單數據存到磁盤, 使用iostream來處理, 避免內存太高. 生成的Uploadable的類型根據表單編碼類型來肯定.
- 全部的upload的url都沒有query參數, 因此用的是ParameterlessRequestConvertible結構體來轉換URLRequestConvertible協議對象.
- upload的12個方法 都是互相調用, 最終的數據編碼, 都在對應的Request模塊
主入口爲:markdown
// MARK: Perform
/// Starts performing the provided `Request`.
///
/// - Parameter request: The `Request` to perform.
func perform(_ request: Request) {
rootQueue.async {
//先在rootQueue中判斷是否請求被取消
guard !request.isCancelled else { return }
//塞入到正在請求的Request集合中
self.activeRequests.insert(request)
//在requestQueue隊列發送請求
self.requestQueue.async {
// 子類必須先case不然就會被識別爲父類了
switch request {
case let r as UploadRequest:
// UploadRequest是DataRequest的子類
self.performUploadRequest(r)
//先建立Uploadable
//而後在rootQueue告知事件監聽器didCreateUploadable, 而後調用performSetupOperations方法
//建立失敗的話先在rootQueue告知監視器didFailToCreateUploadable, 錯誤消息爲createUploadableFailed
//而後在request中決定是否重試
case let r as DataRequest:
self.performDataRequest(r)
//直接調performSetupOperations方法
case let r as DownloadRequest:
self.performDownloadRequest(r)
//對request的downloadable進行斷定
//若是是新建下載, 直接調用performSetupOperations方法
//若是是斷點續傳, 在rootQueue調用didReceiveResumeData方法, 詳見下方斷點續傳部分
case let r as DataStreamRequest:
self.performDataStreamRequest(r)
//直接調performSetupOperations方法
default:
fatalError("Attempted to perform unsupported Request subclass: \(type(of: request))")
}
}
}
}
複製代碼
方法performSetupOperations接受兩個參數: Request對象以及URLRequestConvertible協議對象, 後者來自於request.convertible屬性. 處理成功後, 會調用didCreateURLRequest方法來更新狀態session
func performSetupOperations(for request: Request, convertible: URLRequestConvertible) {
//當前在requestQueue
dispatchPrecondition(condition: .onQueue(requestQueue))
//URLRequestConvertible生成的URLRequest
let initialRequest: URLRequest
do {
initialRequest = try convertible.asURLRequest()
//檢測請求是否有效(get請求不能帶body參數)
try initialRequest.validate()
} catch {
//出錯的話就在rootQueue隊列上報錯誤
rootQueue.async { request.didFailToCreateURLRequest(with: error.asAFError(or: .createURLRequestFailed(error: error))) }
return
}
//在rootQueue通知request,初始化URLRequest成功(使用MutableState記錄狀態, 告知事件監聽器didCreateInitialURLRequest)
rootQueue.async { request.didCreateInitialURLRequest(initialRequest) }
guard !request.isCancelled else { return }
//檢查是否有請求適配器, 內部邏輯:
//1. 判斷request的攔截器跟Session的攔截器都不爲空的話, 就返回生成組合攔截器
//2. 返回request攔截器或者Session攔截器
guard let adapter = adapter(for: request) else {
//沒有攔截器的話直接通知
rootQueue.async { self.didCreateURLRequest(initialRequest, for: request) }
return
}
//使用攔截器中的適配器來預處理請求
adapter.adapt(initialRequest, for: self) { result in
do {
let adaptedRequest = try result.get()
try adaptedRequest.validate()
//通知處理完成
self.rootQueue.async {
request.didAdaptInitialRequest(initialRequest, to: adaptedRequest)
self.didCreateURLRequest(adaptedRequest, for: request)
}
} catch {
//任何錯誤都拋出requestAdaptationFailed錯誤
self.rootQueue.async { request.didFailToAdaptURLRequest(initialRequest, withError: .requestAdaptationFailed(error: error)) }
}
}
}
複製代碼
當建立請求完成, 攔截適配器處理完成以後, 就會來到這裏的邏輯, 除了斷點續傳的請求會執行didReceiveResumeData方法, 其餘的幾個請求都會執行didCreateURLRequest方法, 而後最終都會調用updateStatesForTask方法來更新閉包
func didCreateURLRequest(_ urlRequest: URLRequest, for request: Request) {
dispatchPrecondition(condition: .onQueue(rootQueue))
//通知建立request成功
request.didCreateURLRequest(urlRequest)
guard !request.isCancelled else { return }
//建立URLSessionTask, 基類Request爲實現該方法, 幾個子類各自實現
let task = request.task(for: urlRequest, using: session)
//寫入Session的Request-Task數據對裏保存
requestTaskMap[request] = task
//建立URLSessionTask成功後, request作的相關處理, 線程安全地保存task, 並通知事件監聽器建立task成功
request.didCreateTask(task)
updateStatesForTask(task, request: request)
}
//基本邏輯跟上面類似, 區別就是建立task的方法不一樣, 使用已下載Data建立URLSessionDownloadTask
func didReceiveResumeData(_ data: Data, for request: DownloadRequest) {
dispatchPrecondition(condition: .onQueue(rootQueue))
guard !request.isCancelled else { return }
let task = request.task(forResumeData: data, using: session)
requestTaskMap[request] = task
request.didCreateTask(task)
updateStatesForTask(task, request: request)
}
//上面兩個方法完成後會調用該方法, 開始開始發送請求
func updateStatesForTask(_ task: URLSessionTask, request: Request) {
//確認是在rootQueue隊列更新URLSessionTask的狀態
dispatchPrecondition(condition: .onQueue(rootQueue))
//根據request的狀態來更新對應task的狀態
request.withState { state in
switch state {
case .initialized, .finished:
// 初始化或者請求完成, 啥也不幹
break
case .resumed:
//發送請求
task.resume()
//告知request task開始請求
rootQueue.async { request.didResumeTask(task) }
case .suspended:
//請求掛起
task.suspend()
rootQueue.async { request.didSuspendTask(task) }
case .cancelled:
//先恢復task 再取消, 保證task被取消
task.resume()
task.cancel()
rootQueue.async { request.didCancelTask(task) }
}
}
}
複製代碼
而後等待request各自的RequestDelegate去處理請求落地的邏輯便可
//這兩個邏輯都同樣, 使用 Interceptor 類來組合Session默認的以及每一個請求單獨的 適配器/重試器
func adapter(for request: Request) -> RequestAdapter? {
if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
return Interceptor(adapters: [requestInterceptor, sessionInterceptor])
} else {
return request.interceptor ?? interceptor
}
}
func retrier(for request: Request) -> RequestRetrier? {
if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
return Interceptor(retriers: [requestInterceptor, sessionInterceptor])
} else {
return request.interceptor ?? interceptor
}
}
複製代碼
每個Request對象都持有一個RequestDelegate代理對象用來獲取建立Request時的URLSessionConfiguration以及全局startImmediately, 而且處理錯誤重試與延遲重試邏輯, 指向建立Request的Session, 所以在Session中實現了RequestDelegate協議
Session持有SessionDelegate用來處理Task的代理, SessionDelegate又持有一個RequestTaskMap代理指向Session, 來處理當Task狀態變動時的狀態處理(由於Session持有一個RequestTaskMap對象來儲存Request跟NSURLSessionTask的映射關係), 所以當SessionDelegate響應URLSessionDelegate以及各個NSURLSessionTask的代理回調時, 會回調到Session中的SessionStateProvider相關協議方法中,來根據Task取得對應的Request, 並判斷是否請求完成斷開映射關係。
//全部操做都在rootQueue進行
extension Session: SessionStateProvider {
func request(for task: URLSessionTask) -> Request? {
dispatchPrecondition(condition: .onQueue(rootQueue))
//根據task獲取Request
return requestTaskMap[task]
}
func didGatherMetricsForTask(_ task: URLSessionTask) {
dispatchPrecondition(condition: .onQueue(rootQueue))
//task成功獲取任務指標後的行爲
//在RequestTaskMap結構體中處理, 檢測是否須要斷開request跟task的連接
let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterGatheringMetricsForTask(task)
//waitingCompletions閉包來自於task請求成功後設置的後續操做, 若是成功獲取任務指標後, 執行後續操做, 至此請求完成
if didDisassociate {
waitingCompletions[task]?()
waitingCompletions[task] = nil
}
}
func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) {
dispatchPrecondition(condition: .onQueue(rootQueue))
//檢測是否須要斷開request跟task的連接
let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterCompletingTask(task)
//若是沒有後續邏輯, 直接執行完成回調, 不然把回調保存在waitingCompletions字典中, 等待檢查任務指標後再判斷是否要斷開連接
if didDisassociate {
completion()
} else {
waitingCompletions[task] = completion
}
}
func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? {
dispatchPrecondition(condition: .onQueue(rootQueue))
//HTTPS證書處理
return requestTaskMap[task]?.credential ??
session.configuration.urlCredentialStorage?.defaultCredential(for: protectionSpace)
}
func cancelRequestsForSessionInvalidation(with error: Error?) {
dispatchPrecondition(condition: .onQueue(rootQueue))
//當URLSession出錯時, 並拋出錯誤
requestTaskMap.requests.forEach { $0.finish(error: AFError.sessionInvalidated(error: error)) }
}
}
複製代碼
我的理解記錄~若有錯誤歡迎評論指出,很是感謝~