以創建一個 DataRequest
為例子 
發起請求
創建 SessionManager
順帶也創建了一個 SessionDelegate
持有一個urlSession,持有一個串行的 DispatchQueue A
。
注意,這個不是urlSession
回調方法執行時所在的OperationQueue
創建 Requestable 的 struct,并創建underlying 的 URLSessionDataTask
目前不太清楚作用是什么,但是文檔上的注釋寫著 Helper Types
。
持有一個 urlRequest
。
然后使用這個 Requestable
,創建一個 URLSessionDataTask
注意要在SessionManager
持有的串行隊列中同步創建
sessionManager 創建一個 Request 對象
通過傳入參數 URLSessionDataTask
和 urlSession
。Request
會持有傳入的 urlSession
,并根據URLSessionDataTask
,創建一個 TaskDelegate
。 外部對這個TaskDelegate
的讀取,被鎖保護起來了。
/// The delegate for the underlying task.
open internal(set) var delegate: TaskDelegate {get {taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }return taskDelegate}set {taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }taskDelegate = newValue}
}
創建 TaskDelegate
新創建的 TaskDelegate
會持有傳入的URLSessionDataTask
.
在初始化方法中,會創建一個最大并發數是1的OperationQueue
,并使之處于 suspend
狀態。
sessionManger 持有 Request
創建 Request
之后,會把這個 Request
加到 sessionManger
持有的一個字典中,其讀取方法也被加鎖了。
var requests: [Int: Request] = [:]
private let lock = NSLock()/// Access the task delegate for the specified task in a thread-safe manner.
open subscript(task: URLSessionTask) -> Request? {get {lock.lock() ; defer { lock.unlock() }return requests[task.taskIdentifier]}set {lock.lock() ; defer { lock.unlock() }requests[task.taskIdentifier] = newValue}
}
處理網絡數據
sessionDelegate 接受系統回調
比如方法urlSession(_, task:, didCompleteWithError:)
中,會根據 URLSessionTask
, 找到對應的 Request
。
運行 Request 所有的 validations
運行 TaskDelegate 的任務
所有的任務,都被加到了其持有的 OperationQueue
中。此時處于suspend
狀態,要使其處于可運行的狀態。
然后加到其中的所有任務,都會開始運行。
去掉對 Request 的持有
Request
已經收到并處理完了網絡回調,因此就不必被 sessionDelegate
強持有了。
如果沒有其他的持有者,Request
和其TaskDelegate
也會被釋放。
其中的同步邏輯
sessionManager 的 DispatchQueue
僅用于創建 URLSessionTask
及部分文件目錄操作,都是同步操作。
可能在任何線程創建 URLSessionTask
sessionDelegate 的 lock
僅用于對其持有的Request
的讀取進行加鎖
Request 的 lock
僅對其持有的 TaskDelegate
的讀取進行加鎖
TaskDelegate 的串行 OperationQueue
其中的 Operation
在數據返回后會執行,并且不會并發。
各種 response
方法,都是在其中加入 Operation
TaskDelegate 的 lock
用于對 urlSessionTask
的讀取進行加鎖。
URLSessionTask 如何把整體串起來
- 在
sessionManager
中被創建 - 初始化
Request
時被傳入,用來創建TaskDelegate
- 被
TaskDelegate
持有 - 在
sessionDelegate
中,其taskIdentifier
被作為索引,來獲取Request
- 處理回調時,根據
URLSessionTask
,可以找到對應的Request
,進行對應的處理。