六游的博客小站
Alamofire源码解析专栏(2)- Request
发布于: 2020-08-05 更新于: 2020-10-20 阅读次数: 

Alamofire源码解析专栏文章地址



上篇文章中我们讲到了Session是Alamofire整个系统中的核心类,主要负责请求的创建,分发,管理等,其内部的大部分逻辑都是在与Request类交互,Request类是Alamofire系统中用于代表一个请求的类,在想要仔细阅读Session类的源码之前,我们需要先对Request类有一个了解,所以这一篇文章主要分析Request类以及与其相关的一些类的源码

Request代理-RequestDelegate

Session是管理所有Request的类,Request类本身需要通过代理的方式与Session进行通信,以完成Session对Request的控制,Request代理又RequestDelegate协议定义

1
2
3
4
5
6
7
8
9
10
11
12
public protocol RequestDelegate: AnyObject {
/// 获取到Session中的URLSession的配置
var sessionConfiguration: URLSessionConfiguration { get }
/// 决定Request是否在添加了第一个响应处理函数的时候自动调用resume()启动请求
var startImmediately: Bool { get }
/// 在Request的生命周期结束的时候通知Session清理此Request相关的资源
func cleanup(after request: Request)
/// 在某个Request出现错误的时候,询问Session该Request的重试结果,重试结果使用completion闭包参数传递
func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void)
/// 让Session异步(延时)地重试某个请求
func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?)
}

看完了协议定义,我们来看一下在Session类中具体的协议实现,这个样子我们才能更清楚的了解Request与Session之间交流的方式与内容

1
2
3
4
5
6
7
8
9
10
11
12
13
/// RequestDelegate协议实现的前半部分
extension Session: RequestDelegate {
/// 1
public var sessionConfiguration: URLSessionConfiguration {
session.configuration
}
/// 2
public var startImmediately: Bool { startRequestsImmediately }
/// 3
public func cleanup(after request: Request) {
activeRequests.remove(request)
}
}
  1. 直接返回自身所拥有的URLSession的configuration属性
  2. 直接返回Sessoni自身的startRequestsImmediately属性
  3. request结束之后,Session所做的仅仅是在自己的一个存储活跃Request的集合中将其删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
extension Session {
/// RequestDelegate协议实现的后半部分,较为复杂
/// 为了方便阅读,将Session内部的一个帮助函数也贴了上来
/// 1
func retrier(for request: Request) -> RequestRetrier? {
if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
return Interceptor(retriers: [requestInterceptor, sessionInterceptor])
} else {
return request.interceptor ?? interceptor
}
}
/// 2
public func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void) {
/// 3
guard let retrier = retrier(for: request) else {
rootQueue.async { completion(.doNotRetry) }
return
}
/// 4
retrier.retry(request, for: self, dueTo: error) { retryResult in
self.rootQueue.async {
guard let retryResultError = retryResult.error else { completion(retryResult); return }

let retryError = AFError.requestRetryFailed(retryError: retryResultError, originalError: error)
completion(.doNotRetryWithError(retryError))
}
}
}
/// 5
public func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?) {
rootQueue.async {
/// 7
let retry: () -> Void = {
guard !request.isCancelled else { return }

request.prepareForRetry()
self.perform(request)
}

if let retryDelay = timeDelay {
/// 6
self.rootQueue.after(retryDelay) { retry() }
} else {
retry()
}
}
}
}
  1. retrier是Session类内部提供的一个帮助方法,该方法返回某个request对应的Retrier,这里说的Retrier就是之前在第一篇提到过的遵循RequestRetrier协议的结构,方法返回的retrier主要由Session全局的Interceptor与Request特有的Interceptor拦截器生成。如果全局与Request都有一个自己的拦截器,那么就会将这两个拦截器中的retry方法与adapt融合生成一个新的拦截器并按照RequestRetrier协议类型返回
  2. 该方法由Request出错之后主动调用,来获取重试结果
  3. 首先调用retrier帮助方法,获得一个retrier,如果获取到的retrier为空,则就放弃重试。
  4. 然后调用retrier的retry方法获取到retryResult(是否重试),然后再将这个结果通过Request调用时传进来的completion回调通知给Request
  5. Request接收到是否重试的结果之后调用retryRequest方法让Session重新发起Request
  6. 从Reqeust那里接受一个延时的参数,延时重试Reqeust
  7. 重试Request的逻辑,首先是调用了request的prepareForRetry方法,让Request做出一些重试前的工作(比如重置状态,自增重试次数等),之后Session类的perform方法,这个方法是Session类中的核心方法,用于启动一个Request,之后我们会讲到

Request

Alamofire中的Request模仿了系统中URLSessionTask的结构,存在着许多种不同的请求类,他们都以Request为基类。其中DataRequest、DownloadReqeust、DataStreamRequest都直接继承自基类Request,然后UploadRequest又继承自DataRequest。我们首先来看Request基类中定义了什么东西

State

首先是每个Request都拥有的状态,也是模仿的系统中URLSessionTask的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public enum State {
/// 初始化状态
case initialized
/// resume()被调用后的状态,代表Request请求已经发出
case resumed
/// suspend()被调用后的状态,代表Request进程已经暂停
case suspended
/// cancel()被调用后的状态,代表Request已经关停
case cancelled
/// finish()被调用后的状态,代表所有Request相关的任务都已经处理完毕(包括请求本身与响应数据序列化任务)
case finished
/// 定义了哪些状态转换是可行的
func canTransitionTo(_ state: State) -> Bool {
switch (self, state) {
case (.initialized, _):
return true
case (_, .initialized), (.cancelled, _), (.finished, _):
return false
case (.resumed, .cancelled), (.suspended, .cancelled), (.resumed, .suspended), (.suspended, .resumed):
return true
case (.suspended, .suspended), (.resumed, .resumed):
return false
case (_, .finished):
return true
}
}
}

MutableState

Request中在存储与自己相关的状态信息时并不是选择将一个个的状态直接作为自己的属性存储,而是做了一个中间层,这个中间层就是MutableState,MutableState存储了Request的大部分状态信息,然后Request只需要将MutableState作为自己的属性即可。为什么非要费时费力地增加一个MutableState中间层呢?请继续看,后面我们会说明原因,现在我们先来看一下MutableState的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
struct MutableState {
/// request当前的状态
var state: State = .initialized
/// 上传任务进度更新时会调用的回调函数与回调queue
var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// 下载任务进度更新时会调用的回调函数与回调queue
var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// request发生重定向时会调用的回调
var redirectHandler: RedirectHandler?
/// 响应缓存时会调用的回调
var cachedResponseHandler: CachedResponseHandler?
/// Closure called when the `Request` is able to create a cURL description of itself.
var cURLHandler: ((String) -> Void)?
/// Request中所有待处理的响应序列化任务
var responseSerializers: [() -> Void] = []
/// 每个响应序列化任务都有一个与之对应的任务完成时会调用的回调
var responseSerializerCompletions: [() -> Void] = []
/// 用来标识响应序列化是否完成
var responseSerializerProcessingFinished = false
/// 安全鉴权时会使用到的URLCredential实例
var credential: URLCredential?
/// 由该Request创建的所有URLRequest(说明一个Alamofire的Request对象是有可能创建多个URLRequest的,并不是1对1的关系)
var requests: [URLRequest] = []
/// 由该Request创建的所有URLSessionTask
var tasks: [URLSessionTask] = []
/// tasks产生的所有URLSessionTaskMetrics
var metrics: [URLSessionTaskMetrics] = []
/// 已经进行重试的次数
var retryCount = 0
/// 请求中最后一次出现的Error,可以是来自Alamofire内部的各种调用出错,也可以来自原生请求的执行错误
var error: AFError?
/// 请求是否已经结束
var isFinishing = false
}

根据Session中有多个不同的DispatchQueue属性我们可以推断出,Request是极有可能在多个队列中并行操作的,这样就会带来资源的并发访问安全问题,正常的做法是持有一个锁,在对资源进行操作的时候进行对应的加锁解锁操作,但是属性有这么多,如果在每次都需要在修改属性的时候都额外进行一次加解锁操作,会使程序变得非常复杂,同时编写也更加容易出错,不利于进一步扩展。所以这就是引入MutableState的原因,将所有具有并发访问安全问题的属性放入到这个MutableState中,然后再对这个MutableState属性进行统一的加解锁处理。Alamofire中使用了Swift语言的新特性,使用了Property Wrapper的特性来优雅的实现并发安全的属性访问问题。在Request类的源码中,MutableState的属性是这样定义的

1
2
@Protected
fileprivate var mutableState = MutableState()

上述的属性定义中,使用到了一个名称为Protected的属性包装器,这个属性包装器是Alamofire为需要并发安全访问的属性提供的,接下来我们来分析这个属性包装器的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@propertyWrapper
@dynamicMemberLookup
final class Protected<T> {
/// 类中声明了一个锁,锁的类型根据部署平台变化而有变化
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
private let lock = UnfairLock()
#elseif os(Linux)
private let lock = MutexLock()
#endif
/// 真正被包裹的值
private var value: T

init(_ value: T) {
self.value = value
}

/// 在包裹值中对于读写操作都做了加解锁操作
var wrappedValue: T {
get { lock.around { value } }
set { lock.around { value = newValue } }
}
/// 其中调用的lock.around是对Lock锁的两个扩展方法,是为了更加方便加解锁代码的书写
extension Lock {
func around<T>(_ closure: () -> T) -> T {
lock(); defer { unlock() }
return closure()
}
func around(_ closure: () -> Void) {
lock(); defer { unlock() }
closure()
}
}

var projectedValue: Protected<T> { self }

init(wrappedValue: T) {
value = wrappedValue
}
/// 以下两个方法是为使用工程值进行读写所写的两个便捷方法
func read<U>(_ closure: (T) -> U) -> U {
lock.around { closure(self.value) }
}
@discardableResult
func write<U>(_ closure: (inout T) -> U) -> U {
lock.around { closure(&self.value) }
}

subscript<Property>(dynamicMember keyPath: WritableKeyPath<T, Property>) -> Property {
get { lock.around { value[keyPath: keyPath] } }
set { lock.around { value[keyPath: keyPath] = newValue } }
}
}

使用Swift的属性包装器特性来为类的属性提供并发安全的特性是一种非常优雅的做法,这个东西我们也可以尝试用在自己的项目中,在需要解决并发安全的地方引入这个属性包装器,会使我们的工程代码更加优雅一些

Request类关键属性与生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
```swift
public class Request {
/// 使用UUID为一个request提供一个唯一的标识,同时这个id也帮助了Request实现了Hashable协议
public let id: UUID
/// 内部异步调用使用的串行队列,对应session中的的rootQueue,由Session在创建Request是通过初始化方法传入
public let underlyingQueue: DispatchQueue
/// 所有序列化操作使用的queue,默认与underlyingQueue一样
public let serializationQueue: DispatchQueue
/// 监听器,由session创建时将session的监听器传入
public let eventMonitor: EventMonitor?
/// Request的拦截器
public let interceptor: RequestInterceptor?
/// request的Delegate,与Session类沟通的桥梁,最开始已经讲解过
public private(set) weak var delegate: RequestDelegate?

/// mutableState记录Request大部分的可变状态信息,上面已经讲解过
@Protected
fileprivate var mutableState = MutableState()
/// 存储着validator验证器队列,该属性也使用了@Protected属性包装器修饰,来保证并发安全性
@Protected
fileprivate var validators: [() -> Void] = []
}

上面介绍了Request类中的成员属性,下面来介绍Request类中的一些方法,最开始是Request类中比较重要的与生命周期相关的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
public class Request {
/// 启动Request的方法,调用该方法将Request的状态设置为resumed
/// 如果成功将Request的状态设置为resumed,那么resume Request的task列表中的最后一个URLSessionTask
@discardableResult
public func resume() -> Self {
$mutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.resumed) else { return }
// 更改状态
mutableState.state = .resumed
// 发出通知
underlyingQueue.async { self.didResume() }
// 获取task列表中的最后一个URLSessionTask并对其进行resume操作
guard let task = mutableState.tasks.last, task.state != .completed else { return }
task.resume()
// 发出通知
underlyingQueue.async { self.didResumeTask(task) }
}

return self
}
/// 关闭并清理Request的方法,子类中的cleanup方法需要调用super的方法
/// 基类中该方法做的仅仅是:通过代理通知Session清除与自己相关的资源
func cleanup() {
delegate?.cleanup(after: self)
}

/// 暂停Request的方法,调用该方法将Request的状态设置为suspend
/// 如果成功将Request的状态设置为suspend,那么suspend Request的task列表中的最后一个URLSessionTask
@discardableResult
public func suspend() -> Self {
$mutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.suspended) else { return }
// 更改状态
mutableState.state = .suspended
// 发出通知
underlyingQueue.async { self.didSuspend() }
// 获取task列表中的最后一个URLSessionTask并对其进行suspend操作
guard let task = mutableState.tasks.last, task.state != .completed else { return }
task.suspend()
// 发出通知
underlyingQueue.async { self.didSuspendTask(task) }
}

return self
}
/// 关闭Request的方法,调用该方法将Request的状态设置为cancel
/// 如果成功将Request的状态设置为cancel,那么cancel Request的task列表中的最后一个URLSessionTask
@discardableResult
public func cancel() -> Self {
$mutableState.write { mutableState in
guard mutableState.state.canTransitionTo(.cancelled) else { return }
// 更改状态
mutableState.state = .cancelled
// 发出通知
underlyingQueue.async { self.didCancel() }
// 获取task列表中的最后一个URLSessionTask并对其进行suspend操作
guard let task = mutableState.tasks.last, task.state != .completed else {
underlyingQueue.async { self.finish() }
return
}
// Resume to ensure metrics are gathered.
task.resume()
task.cancel()
// 发出通知
underlyingQueue.async { self.didCancelTask(task) }
}

return self
}
/// 结束Request的方法,调用该方法将Request的状态设置为finish
/// 如果成功将Request的状态设置为cancel,那么就开始处理响应序列化任务
func finish(error: AFError? = nil) {
dispatchPrecondition(condition: .onQueue(underlyingQueue))
guard !mutableState.isFinishing else { return }
// 更改状态
mutableState.isFinishing = true
if let error = error { self.error = error }
// 开始处理响应序列化任务
processNextResponseSerializer()
// 发出通知
eventMonitor?.requestDidFinish(self)
}
/// request出错时调用,该方法会判断这个request是retry还是直接结束
func retryOrFinish(error: AFError?) {
dispatchPrecondition(condition: .onQueue(underlyingQueue))
guard let error = error, let delegate = delegate else { finish(); return }
// 向自己的代理询问该请求是否可以进行重试
delegate.retryResult(for: self, dueTo: error) { retryResult in
switch retryResult {
// 如果得到的结果是不能进行重试,那么就调用finish方法,结束Request的生命周期
case .doNotRetry:
self.finish()
case let .doNotRetryWithError(retryError):
self.finish(error: retryError.asAFError(orFailWith: "Received retryError was not already AFError"))
// 如果得到的结果是可以进行重试,那么就通过代理委托Session类重新发起这个请求
case .retry, .retryWithDelay:
delegate.retryRequest(self, withDelay: retryResult.delay)
}
}
}
/// 在Request准备进行重试之前会被调用
/// 重试次数+1,并调用reset方法重置一些状态,为即将到来的重试做准备
func prepareForRetry() {
dispatchPrecondition(condition: .onQueue(underlyingQueue))
// 重试次数+1并调用reset方法
$mutableState.write { $0.retryCount += 1 }
reset()
// 发出通知
eventMonitor?.requestIsRetrying(self)
}
/// 重置Request一些状态,包括出现的错误、上传下载进度以及序列化任务
func reset() {
error = nil
uploadProgress.totalUnitCount = 0
uploadProgress.completedUnitCount = 0
downloadProgress.totalUnitCount = 0
downloadProgress.completedUnitCount = 0

$mutableState.write { state in
state.isFinishing = false
state.responseSerializerCompletions = []
}
}
}

Request类序列化任务处理流程

上述分析了一些与Request整个生命周期相关的方法代码,下面开始分析与Request序列化任务相关的代码。在开始之前我们要了解Request中的序列化任务是什么,在我们开发使用Alamofire是,经常使用AF.request(…).reponse(…)或者AF.request(…).reponseJson(…)这样子的链式调用来处理一个网络请求,最后面调用的response()与responseJson()方法就是在为当前请求的Request添加一个响应的序列化任务,序列化任务主要负责将网络返回的响应序列化成你像要的数据并在完成任务之后调用对应的回调。

Request类中对于序列化任务的处理逻辑十分复杂,我也是前前后后看了好多遍才理解其内部运行的机制,虽然代码量不少,但是逻辑非常的绕。我这里会将其内部大概的运行机制先描述一遍,希望能使你们在观看以下源码的时候理解起来可以更加轻松一些。当然,一时看不懂请先不要着急,看完一遍有个大概地印象之后,再细细品味每个方法的作用便可参透。


我们对Request调用response或者responseJSON等序列化方法,想要拿到请求之后的数据的时候,实际上就是在向Request中添加一个序列化任务,每一个序列化任务都对应一个序列化任务回调,该回调会在序列化任务结束的时候调用。我们用户通过response或者responseJSON方法传入进去的闭包大多数情况下就直接被作为这个序列化任务的回调,但是呢,Alamofire就在这里玩了一个骚操作,序列化任务与序列化回调并不会同时都被加入到Request中去,而是只添加一个序列化任务并通知Request开始处理未处理的序列化任务或者序列化闭包,然后在这个序列化任务的末尾(也就是真正的序列化都已经执行完毕,但这个序列化任务闭包还没结束的时候),将该序列化任务对应的回调添加进Request中去,同时也会去通知Request去处理未处理的序列化任务或者序列化闭包。

PS:这里的逻辑很绕,我的文本表达能力也不是很好,应该没有特别清晰地将这段流程表达清楚,大家可以看下面更具有逻辑性的描述。另外这里为什么要搞一套这么复杂的流程来处理序列化任务的问题,笔者目前还是不太清楚的,仅仅是了解了其基本流程(因为还存在其他更为直接的方法来处理序列化任务以及任务的回调),等我探索到原因之后一定火速更新到这里。


同时我还提供了两个在不同情况下,序列化任务的处理流程,你在阅读代码的时候,可以分别将这两种代码带入到源码中去,便阅读源码边验证下面我所书写的流程,应该会有不小的收获

当一个请求在同一时间只有一个序列化任务被添加的时候,执行的流程就是这个样子的:

  1. 序列化任务被加入到Request中
  2. 开始处理这个序列化任务(通过serializationQueue异步处理)
  3. 在序列化任务即将完成时,序列化任务对应的回调将会被加入到Request中
  4. 开始处理这个回调
  5. 回调处理完毕,清理Request的资源,并设置相关标识符,表示自己已经完成所有任务

当一个请求在同一时间被添加了两个序列化任务的时候,执行的流程是这个样子的:

  1. 序列化任务A被添加到Request中
  2. 开始处理序列化任务A(通过serializationQueue异步处理)
  3. 序列化任务B被添加到Request中
  4. 在序列化任务B被添加时,通过Request的一些状态标识发现该Request正在处理其他的序列化任务,就停止自己的下一步行为了
  5. 序列化任务A即将完成时,序列化任务A对应的回调将会被加入到Request中
  6. Request发现此时还有未经过处理的序列化任务(任务B),然后就开始处理序列化任务B(通过serializationQueue异步处理)
  7. 序列化任务B即将完成时,序列化任务B对应的回调将会被加入到Request中
  8. Request发现此时拥有的所有序列化任务都处理完了,然后就清除所有的序列化任务,执行先前被添加到Request中的所有回调(回调A,回调B),并清除自身拥有的所有回调。最后清理Request的资源,并设置相关标识符,表示自己已经完成所有任务

下面是源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/// 为了更好的理解Request中处理响应与回调的流程
/// 这里先用一个最简单的response函数作为举例演示一下
extension DataRequest {
/// 调用response函数取得请求的结果,该方法实际上不会对网络请求返回的Data做任何处理,直接将原数据作为结果
@discardableResult
public func response(queue: DispatchQueue = .main, completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self {
// 调用appendResponseSerializer,向Request中添加一个序列化任务
appendResponseSerializer {
// 创建一个用来表示网络请求的结果的对象
let result = AFResult<Data?>(value: self.data, error: self.error)

self.underlyingQueue.async {
let response = DataResponse(request: self.request,
response: self.response,
data: self.data,
metrics: self.metrics,
serializationDuration: 0,
result: result)
// 发出通知
self.eventMonitor?.request(self, didParseResponse: response)
// 在序列化任务结束的前一刻,会调用responseSerializerDidComplete方法将此次序列化任务的完成回调添加到Request中
self.responseSerializerDidComplete { queue.async { completionHandler(response) } }
}
}

return self
}
}
public class Request {
/// 该方法向request的ResponseSerializer列表中添加一个序列化处理任务
func appendResponseSerializer(_ closure: @escaping () -> Void) {
$mutableState.write { mutableState in
// 添加序列化任务
mutableState.responseSerializers.append(closure)
// 这里更改状态是为了在方法的末尾能够成功重新resume这个request
if mutableState.state == .finished {
mutableState.state = .resumed
}
// 如果当前没有正在处理的序列化任务,就调用processNextResponseSerializer方法立即对刚添加的这个任务进行处理
if mutableState.responseSerializerProcessingFinished {
underlyingQueue.async { self.processNextResponseSerializer() }
}
// 如果session中的startImmediately设置为了true,那么在添加了一个序列化任务之后会立马resume这个Request
if mutableState.state.canTransitionTo(.resumed) {
underlyingQueue.async { if self.delegate?.startImmediately == true { self.resume() } }
}
}
}
/// 该方法向request中添加一个序列化处理任务的闭包,随后调用processNextResponseSerializer方法让Request来处理
func responseSerializerDidComplete(completion: @escaping () -> Void) {
$mutableState.write { $0.responseSerializerCompletions.append(completion) }
processNextResponseSerializer()
}
/// 该方法处理Request的序列化任务或者序列化任务回调
func processNextResponseSerializer() {
// 查看Request中是否还有没有进行处理过的序列化任务,如果没有
// 则获取到所有的回调,并执行他们,最后进行清理工作,相当于进行了一个清底行动
guard let responseSerializer = nextResponseSerializer() else {
var completions: [() -> Void] = []

$mutableState.write { mutableState in
completions = mutableState.responseSerializerCompletions
mutableState.responseSerializers.removeAll()
mutableState.responseSerializerCompletions.removeAll()

if mutableState.state.canTransitionTo(.finished) {
mutableState.state = .finished
}
mutableState.responseSerializerProcessingFinished = true
mutableState.isFinishing = false
}

completions.forEach { $0() }
cleanup()
return
}
// 如果查找到还有没有进行处理过的序列化任务,那就调用这个闭包执行序列化任务
serializationQueue.async { responseSerializer() }
}
/// 该方法查找Request中是否还有没有进行处理过的序列化任务
func nextResponseSerializer() -> (() -> Void)? {
var responseSerializer: (() -> Void)?

$mutableState.write { mutableState in
// 因为每一个序列化任务的回调都是在序列化任务即将要完成时添加到Request中的
// 所以我们可以使用Request内部的回调的个数来指示当前序列化任务已经完成的个数
// 然后就有了以下的操作,用回调个数来作为索引去序列化任务数组中取值,如果没有取到就说明所有的序列化任务都已经处理完成了
let responseSerializerIndex = mutableState.responseSerializerCompletions.count

if responseSerializerIndex < mutableState.responseSerializers.count {
responseSerializer = mutableState.responseSerializers[responseSerializerIndex]
}
}

return responseSerializer
}
}

Request类的其他函数

除了上面的那些重要并且逻辑比较难懂的方法之外,Request类中还有一系列简单易懂的函数,有些函数是负责将Request的一些状态变更作为通知发送给Alamofire的通知中心,比如下面的一些例子:

1
2
3
4
5
6
7
// 该方法很简单的向Alamofire中的通知中心eventMonitor发送了task已经被resume的通知
// 诸如此类的方法还有许多,大多都是跟下面一样的套路,所以就不一一罗列
// 这些方法的定义在Alamofire源码的Request.swift文件中,如果有兴趣可以自行去文件中查找
func didResumeTask(_ task: URLSessionTask) {
dispatchPrecondition(condition: .onQueue(underlyingQueue))
eventMonitor?.request(self, didResumeTask: task)
}

还有一些函数是对外提供API接口,使用户可以使用Request的特定功能的函数,比如下面一些例子:

1
2
3
4
5
6
7
8
9
// 以下函数接收一个ProgressHandler,将其作为下载进度更新时的回调函数
// 这些方法的套路基本上是接收用户传入的一个东西,并将其设置到Request的属性中去
// 另外值得注意的是:这些方法的末尾都会返回self,这也是Alamofire中可以链式调用的一个原因
// 同样,此类的更多方法就不一一赘述,如果有兴趣可以自行去文件中查找
@discardableResult
public func downloadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self {
mutableState.downloadProgressHandler = (handler: closure, queue: queue)
return self
}

除此之外还有一些函数值得大家去注意,那就是SessionDelegate与Request进行交互的方法。但这些函数并不存在于Request类中,前面我们就提到过Alamofire中的请求是一个系统,并不是单单一个类,并且Request在请求系统中扮演的角色只是一个抽象基类,是不会被真正使用的,其类内部只是定义了一些Request所共有的关键属性与生命周期。Request的每个子类都有自己需要完成的任务,不同的任务也就需要与SessionDelegate有不同种类的交互。这里我们举一个DataRequest的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 以下函数会接收一个从代理那里收到的服务器响应的数据
// 接收到之后会将数据拼接到自身的一个用来存储数据的属性之上,并在之后更新Request的下载进度
// 同时此举动会触发DownloadProgressHandler回调的调用
// 这类函数并没有固定的套路,都是与特定的功能强相关的代码,但是基本上都与我们在使用原生网络系统进行开发时的遇到的问题一致
// 所以也就不一一赘述,如果有兴趣可以自行去文件中查找
func didReceive(data: Data) {
if self.data == nil {
mutableData = data
} else {
$mutableData.write { $0?.append(data) }
}

updateDownloadProgress()
}

至此本篇关于Request类源码阅读的也就先告一段落了,希望大家都能在源码阅读的道路上有自己的收获

--- 本文结束 The End ---