1. 程式人生 > >Alamofire原始碼導讀二:發起請求及內部加鎖的邏輯

Alamofire原始碼導讀二:發起請求及內部加鎖的邏輯

以建立一個 DataRequest 為例子

發起請求

建立 SessionManager

順帶也建立了一個 SessionDelegate
持有一個urlSession,持有一個序列的 DispatchQueue A
注意,這個不是urlSession 回撥方法執行時所在的OperationQueue

建立 Requestable 的 struct,並建立underlying 的 URLSessionDataTask

目前不太清楚作用是什麼,但是文件上的註釋寫著 Helper Types
持有一個 urlRequest
然後使用這個 Requestable,建立一個 URLSessionDataTask


注意要在SessionManager持有的序列佇列中同步建立

sessionManager 建立一個 Request 物件

通過傳入引數 URLSessionDataTaskurlSession
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,進行對應的處理。