Alamofire源码导读二:发起请求及内部加锁的逻辑
以创建一个 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
,进行对应的处理。