以建立一個 DataRequest
爲例子 網絡
發起請求
建立 SessionManager
順帶也建立了一個 SessionDelegate
持有一個urlSession,持有一個串行的 DispatchQueue A
。
注意,這個不是urlSession
回調方法執行時所在的OperationQueue
session
建立 Requestable 的 struct,並建立underlying 的 URLSessionDataTask
目前不太清楚做用是什麼,可是文檔上的註釋寫着 Helper Types
。
持有一個 urlRequest
。
而後使用這個 Requestable
,建立一個 URLSessionDataTask
注意要在SessionManager
持有的串行隊列中同步建立併發
sessionManager 建立一個 Request 對象
經過傳入參數 URLSessionDataTask
和 urlSession
。
Request
會持有傳入的 urlSession
,並根據URLSessionDataTask
,建立一個 TaskDelegate
。 外部對這個TaskDelegate
的讀取,被鎖保護起來了。 url
/// 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
狀態。 spa
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
。 code
運行 Request 全部的 validations
運行 TaskDelegate 的任務
全部的任務,都被加到了其持有的 OperationQueue
中。此時處於suspend
狀態,要使其處於可運行的狀態。
而後加到其中的全部任務,都會開始運行。 對象
去掉對 Request 的持有
Request
已經收到並處理完了網絡回調,所以就沒必要被 sessionDelegate
強持有了。
若是沒有其餘的持有者,Request
和其TaskDelegate
也會被釋放。 blog
其中的同步邏輯
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
,進行對應的處理。