AlamoFire 源码浅析

文章目录
  1. 1. 一、AlamoFire 使用
  2. 2. 二、 AF命名空间
  3. 3. 三、 URLConvertible
  4. 4. 请求方式
  5. 5. 编码器
    1. 5.1. URLEncoding 类
    2. 5.2. JSONEncoding
  6. 6. 拦截器部分(RequestInterceptor适配、重试)
    1. 6.1. RequestAdapter 协议
    2. 6.2. Result 表示结果的枚举
    3. 6.3. RetryResult重试枚举
    4. 6.4. RequestRetrier协议
    5. 6.5. RequestInterceptor 协议
    6. 6.6. Adapter 类
    7. 6.7. Retrier 类
    8. 6.8. Interceptor类
  7. 7. ServerTrustManager–服务信任管理
    1. 7.1. ServerTrustEvaluating 评估器协议
    2. 7.2. DefaultTrustEvaluator
    3. 7.3. RevocationTrustEvaluator 类
    4. 7.4. PinnedCertificatesTrustEvaluator
    5. 7.5. PublicKeysTrustEvaluator
  8. 8. RedirectHandler – 重定向处理
    1. 8.1. Redirector 结构体
  9. 9. CachedResponseHandler 缓存协议
    1. 9.1. ResponseCacher 结构体
  10. 10. RequestDelegate 请求代理
    1. 10.1. SessionStateProvider
    2. 10.2. 小小节
  11. 11. 序列化响应
    1. 11.1. DataResponseSerializerProtocol 协议
    2. 11.2. DownloadResponseSerializerProtocol 协议
    3. 11.3. ResponseSerializer
    4. 11.4. DataPreprocessor 数据预处理器
    5. 11.5. ResponseSerializer 协议扩展
    6. 11.6. DataRequest 在序列化文件中的扩展
  12. 12. Request
    1. 12.1. 初始状态部分
    2. 12.2. 可变状态部分
    3. 12.3. 进度部分
    4. 12.4. 重定向、缓存
    5. 12.5. response
    6. 12.6. task
    7. 12.7. 内部功能
    8. 12.8. 验证响应
  13. 13. Protector
  14. 14. session
  15. 15. RequestTaskMap
  16. 16. Extended命名作用域
  17. 17. 学习到的知识
    1. 17.1. OptionSet

AlamoFire 学习

一、AlamoFire 使用

1
2
3
4
5
6
7
///创建一个请求
let request = AF.request("https://httpbin.org/post", method: .post)

//添加一个完成Block,序列化器序列的类型String
request.responseString { response in
requestComplete(response.response, response.result)
}

下面是两个函数的定义

1
2
3
4
5
6
7
8
9
10
public static func request(_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest

public func responseString(queue: DispatchQueue = .main,
encoding: String.Encoding? = nil,
completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self

首先我定的策略是农村包围城市,先了解request函数的参数中使用的类型,完事后,再进入函数体内部,了解原理。

二、 AF命名空间

Alamofire是入口文件,文件中定义了一个枚举,充当命名空间的作用。

1
2
3
4
5
6
7
8
9
10
11
12
public enum AF {
static let version = "5.0.0-rc.3"

public static func request(_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest {
....
}
}

使用的时候调用AF.request。防止request和其他的request冲突,包装在AF中,起到命名空间的作用。

三、 URLConvertible

URLConvertible 是一个协议。

1
2
3
public protocol URLConvertible {
func asURL() throws -> URL
}

这个协议的作用是创建一个URL对象。并且String、URL、URLComponents结构都遵守了这个协议,那么, 好处是什么呢?

扩大了参数的类型,也就是说可以给request方法传递String、URL、URLComponents类型的参数,函数内部使用asURL方法统一获取URL对象。

请求方式

请求方式定义为HTTPMethod结构体类型,封装了请求的方式。

编码器

编码器定义一个协议,所有的编码器准守改协议 – ParameterEncoding

1
2
3
public protocol ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}

该协议定义了如何将请求参数编码到请求urlRequest中。

alamofire中定义了URLEncoding、JSONEncoding两种编码器实现了ParameterEncoding协议。

URLEncoding 类

遵守ParameterEncoding协议,创建基于url-encoded的查询串,设置或添加到URL上,或者HTTP的body中。对于集合类型的参数如何编码,没有公开的规范,所以对于数组编码为形如foo[]=1&foo[]=2的格式,字典形如foo[bar]=baz格式。可以通过ArrayEncoding删除中括号,BoolEncoding可以配置布尔值如何编码(比如true 1,false 0)

一、Destination 枚举

url编码的查询串是否添加到已有查询串,还是添加到HTTP Body中

1
2
3
4
5
6
7
8
9
10
11
12
13
public enum Destination {
/// GET、HEAD、DELETE 查询,其他的请求放在Body中
case methodDependent
case queryString
case httpBody
func encodesParametersInURL(for method: HTTPMethod) -> Bool {
switch self {
case .methodDependent: return [.get, .head, .delete].contains(method)
case .queryString: return true
case .httpBody: return false
}
}
}

二、 ArrayEncoding 枚举

配置Array参数如何编码

1
2
3
4
5
6
7
8
9
10
11
12
public enum ArrayEncoding {
case brackets
case noBrackets
func encode(key: String) -> String {
switch self {
case .brackets:
return "\(key)[]"
case .noBrackets:
return key
}
}
}

三、 BoolEncoding

配置Bool参数如何编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum BoolEncoding {
/// Encode `true` as `1` and `false` as `0`. This is the default behavior.
case numeric
/// Encode `true` and `false` as string literals.
case literal

func encode(value: Bool) -> String {
switch self {
case .numeric:
return value ? "1" : "0"
case .literal:
return value ? "true" : "false"
}
}
}

四、 属性

  1. default 返回编码方式是.methodDependent的编码器(URLEncoding)
  2. queryString 返回编码方式是.queryString的编码器(URLEncoding)
  3. httpBody 返回编码方式是.httpBody的编码器(URLEncoding)
  4. destination 目标编码方式 (实例属性)
  5. arrayEncoding 编码使用的array的编码方式 (实例属性)
  6. boolEncoding 编码器编码Bool属性使用的编码方式 (实例属性)

五 方法

实现了编码方法

JSONEncoding

使用JSONSerialization 将请求参数编码为JSON格式 ,并将Content type 设置为 application/json

拦截器部分(RequestInterceptor适配、重试)

RequestAdapter 协议

可以翻译为请求适配器,可以对URLRequest inspect、ptionally adapt,适配后,会执行completion block。

1
2
3
4
public protocol RequestAdapter {
/// Inspects and adapts the specified `URLRequest` in some manner and calls the completion handler with the Result.
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void)
}

Result 表示结果的枚举

封装了成功和失败两个关联值的枚举

RetryResult重试枚举

封装了立即重试(retry)、延迟重试(retryWithDelay,关联了延时时间)、不重试(doNotRetry)、某种错误不重试(doNotRetryWithError,关联了某种类型的错误)

RequestRetrier协议

RequestRetrier协议封装了:请求被session manager执行后,并遇到错误,是否重试。

1
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void)

当决定重试时,通过completion完成重试

RequestInterceptor 协议

准守RequestAdapter和RequestRetrier协议。

Adapter 类

基于闭包的RequestAdapter类型,准守RequestInterceptor协议

Retrier 类

基于闭包的RequestRetrier,准守RequestInterceptor协议

Interceptor类

可以使用多个RequestAdapter、RequestRetrier进行拦截,继承于RequestInterceptor。

内部存储多个RequestAdapter、RequestRetrier进行拦截

ServerTrustManager–服务信任管理

管理 ServerTrustEvaluating和host的映射。

1
2
3
4
5
6
7
8
9
open class ServerTrustManager {
/// 是否所有host都需要被评估,默认true
public let allHostsMustBeEvaluated: Bool

/// host 与host对应的policies的字典
public let evaluators: [String: ServerTrustEvaluating]

///返回host对应的评估器(ServerTrustEvaluating)
open func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating?;

ServerTrustEvaluating 评估器协议

描述了评估服务器信任的API

1
func evaluate(_ trust: SecTrust, forHost host: String) throws

评估给定host的trust是否可行

DefaultTrustEvaluator

使用服务器默认信任评估的评估器,可以控制是否验证挑战(challenge)提供的host

评估思路:

  1. host ->SecPolicy
  2. 调用SecTrustSetPolicies函数,给SecTrust设置策略
  3. 调用SecTrustEvaluateWithError,验证SecTrust

RevocationTrustEvaluator 类

使用默认的和撤销服务信任评估的评估器,继承ServerTrustEvaluating协议。

该信任评估和DefaultTrustEvaluator 的主要区别是创建策略的方法不同,使用的函数是SecPolicyCreateRevocation。

PinnedCertificatesTrustEvaluator

使用证书评估服务器,只要任何一张固定证书匹配服务器的任何一张证书,就认为服务器是可信的。

自签名证书:

  1. 调用SecTrustSetAnchorCertificates 函数,将证书添加到trust中。trust包含需要验证的证书、验证使用的策略、可选的验证证书的证书(AnchorCertificates )
  2. SecTrustSetAnchorCertificatesOnly ,必须调用的,如果不调用,只用使用AnchorCertificates验证证书。调用了可以使用其他的证书,比如系统证书?
  3. 调用 SecTrustEvaluateWithError函数评估服务器信任

正常情况:

判断固定证书是否包含在服务器的证书中,调用Set的 isDisjoint方法。

证书的读取方法

  1. PinnedCertificatesTrustEvaluator初始哈方法中,调用了Bundle.main.af.certificates函数。
  2. Bundle的扩展中有certificates计算属性,读取.cer, CER, .crt, .CRT, .der后缀文件。

PublicKeysTrustEvaluator

使用公钥评估服务器信任。

RedirectHandler – 重定向处理

如何处理“服务端返回的重定向响应”—要求重定向到新的请求。

1
2
3
4
func task(_ task: URLSessionTask,
willBeRedirectedTo request: URLRequest,
for response: HTTPURLResponse,
completion: @escaping (URLRequest?) -> Void)

Redirector 结构体

是一个便利的RedirectHandler,可以follow、not follow、modify a redirect。

扩展里面做了默认实现,

  1. follow,执行completion Block,参数是重定向指定的新请求。
  2. not fllow 执行completion Block,参数是nil
  3. 如果是modify,使用modify关联的Closure创建新的请求,然后执行completion Block,参数是修改过的请求。

CachedResponseHandler 缓存协议

初始data task 是否缓存响应。

1
2
3
func dataTask(_ task: URLSessionDataTask,
willCacheResponse response: CachedURLResponse,
completion: @escaping (CachedURLResponse?) -> Void)

completion 是执行缓存操作的Block,有三种情况

  1. 服务器提供的缓存响应
  2. 修改响应的缓存
  3. nil,不缓存

ResponseCacher 结构体

ResponseCacher是一个便利的缓存处理器(CachedResponseHandler),可以处理缓存、不缓存、修改缓存。

RequestDelegate 请求代理

执行URLSessionDelegate的方法的类。

1
2
private let fileManager: FileManager
weak var stateProvider: SessionStateProvider?

SessionStateProvider

SessionStateProvider协议提供Session的各种状态,包括主要的三要素:信任评估、 重定向、缓存。

1
2
3
var serverTrustManager: ServerTrustManager? { get }
var redirectHandler: RedirectHandler? { get }
var cachedResponseHandler: CachedResponseHandler? { get }

一、SessionStateProvider功能:

1
2
3
4
5
6
7
protocol SessionStateProvider: AnyObject {
func request(for task: URLSessionTask) -> Request? //创建请求
func didGatherMetricsForTask(_ task: URLSessionTask) //度量完成
func didCompleteTask(_ task: URLSessionTask)//任务完成
func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential?//创建凭证
func cancelRequestsForSessionInvalidation(with error: Error?)//session非法时,取消请求
}

二、 执行URLSessionDelegate的代理方法

1
2
3
4
5
open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {

eventMonitor?.urlSession(session, didBecomeInvalidWithError: error)
stateProvider?.cancelRequestsForSessionInvalidation(with: error)
}

session无效后,取消请求。

三、 URLSessionTaskDelegate 的代理方法

插曲,下面是挑战的结构

1
2
3
4
5
6
7
8
9
10
URLAuthenticationChallenge(挑战)
URLProtectionSpace(保护空间)
realm 认证域
host
port
authenticationMethod
proposedCredential: URLCredential(凭证)
用户名密码类型凭证
证书类型凭证
被接受的specified trust

3.1 认证代理方法

1
2
3
4
open func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

根据挑战URLAuthenticationChallenge,创建凭证URLCredential。调用completionHandler接受挑战,参数是challenge.protectionSpace.authenticationMethod、凭证。

3.1 数据发送代理方法

1
2
3
4
5
open func urlSession(_ session: URLSession,
task: URLSessionTask,
didSendBodyData bytesSent: Int64,
totalBytesSent: Int64,
totalBytesExpectedToSend: Int64)

3.3 需要请求体代理方法

1
2
3
open func urlSession(_ session: URLSession,
task: URLSessionTask,
needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)

3.4 重定向代理方法

1
2
3
4
5
open func urlSession(_ session: URLSession,
task: URLSessionTask,
willPerformHTTPRedirection response: HTTPURLResponse,
newRequest request: URLRequest,
completionHandler: @escaping (URLRequest?) -> Void)

3.5 度量完成

1
open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics)

3.6 请求完成

1
2
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
eventMonitor?.urlSession(session, task: task, didCompleteWithError: error)

四、 URLSessionDataDelegate代理

1
2
3
4
5
6
7
8
//收到数据
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

//缓存响应
open func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
willCacheResponse proposedResponse: CachedURLResponse,
completionHandler: @escaping (CachedURLResponse?) -> Void)

小小节

SessionDelegate 主要就是执行URLSession的代理。每个代理的工作是

  1. 调用事件监控对应的方法(EventMonitor)
  2. 二是调用SessionStateProvider中定制方法、或者SessionStateProvider中的评估器、重定向器、缓冲器方法。

所以,SessionStateProvider中的评估器、重定向器、缓冲器,就是为了将复杂的功能分离出去,独立为模块。

序列化响应

DataResponseSerializerProtocol 协议

DataResponseSerializerProtocol 协议

1
2
3
4
5
6
public protocol DataResponseSerializerProtocol {
/// The type of serialized object to be created.
associatedtype SerializedObject

func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> SerializedObject
}

定义了序列化的方法

DownloadResponseSerializerProtocol 协议

1
2
3
4
5
public protocol DownloadResponseSerializerProtocol {
/// The type of serialized object to be created.
associatedtype SerializedObject
func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> SerializedObject
}

定义了下载请求序列化的方法

ResponseSerializer

能够处理数据和下载的序列化器

1
2
3
4
5
6
7
public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol {
/// 准备数据
var dataPreprocessor: DataPreprocessor { get }
/// `HTTPMethod`s for which empty response bodies are considered appropriate.
var emptyRequestMethods: Set<HTTPMethod> { get }
/// HTTP response codes for which empty response bodies are considered appropriate.
var emptyResponseCodes: Set<Int> { get }

DataPreprocessor 数据预处理器

序列化前的数据处理

1
2
3
4
5
public protocol DataPreprocessor {
/// Process `Data` before it's handled by a serializer.
/// - Parameter data: The raw `Data` to process.
func preprocess(_ data: Data) throws -> Data
}

ResponseSerializer 协议扩展

该部分扩展添加了是否允许空响应的识别。

一、 判断请求是否允许空响应,从请求方式判断,Head允许

1
2
3
4
5
public func requestAllowsEmptyResponseData(_ request: URLRequest?) -> Bool? {
return request.flatMap { $0.httpMethod }
.flatMap(HTTPMethod.init)
.map { emptyRequestMethods.contains($0) }
}

二、 判断响应是否允许空响应,从响应码判断,204 205 允许

1
2
3
4
public func responseAllowsEmptyResponseData(_ response: HTTPURLResponse?) -> Bool? {
return response.flatMap { $0.statusCode }
.map { emptyResponseCodes.contains($0) }
}

DataRequest 在序列化文件中的扩展

一、 默认的只添加序列化完成的闭包,没有序列化功能

1
public func response(queue: DispatchQueue = .main, completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self

二、 添加一个包含序列化器的完成处理闭包

1
2
3
4
@discardableResult
public func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void)

内部调用appendResponseSerializer添加了一个序列化的block,block内部的工作

  1. 调用responseSerializer的序列化方法 serialize
  2. 将序列化的结果封装到result中,包含序列化完的数据、错误
  3. 封装DataResponse类型的response,包括request、response、data、serializationDuration、result
  4. 如果!(有错误有代理) 将完成block添加的responseSerializerDidComplete中
  5. 如果 (有错误有代理) ,调用重试结果

重试的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
序列化发生错误时,参数是序列化完成hander :completionHandler
|
| 调用
|
Session->retryResult函数: retryCompletion
|
| 创建retryCompletion逻辑如下,参数是RetryResult
|
1. 如果不重试didComplete = completionHandler(response)
2. 有错误不重试,组装错误,didComplete =completionHandler(response)
3. 重试,执行重试操作
4. didComplete存储到session的 responseSerializerCompletions
|
| retryResult函数内部逻辑
|
1. 取得retrier:RequestRetrier
2. 调用retry : 完成block,命名为 retryCompletion1
|
A. 重试没有错误,执行retryCompletion(result)
B. 有错误,retryCompletion(.doNotRetryWithError(retryError))
|
| retry函数的逻辑
|
执行retryHandler函数: retryCompletion1

上面是最外层,最外层的block最小,越下面的封装,block越大,最内侧的函数完成后执行最大的block,一直向最外层(顶部最小)扩展

添加一个string类型的序列化器

1
2
3
public func responseString(queue: DispatchQueue = .main,
encoding: String.Encoding? = nil,
completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self

添加一个JSON类型的序列化器

1
2
3
public func responseJSON(queue: DispatchQueue = .main,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse<Any>) -> Void) -> Self

Request

Request is the common superclass of all Alamofire request types and provides common state, delegate, and callback handling.

request是有状态的,通过内部枚举State表征。状态通过resume、suspend、cancel函数改变。

初始状态部分

1
2
3
4
5
6
id: UUID 为request提供唯一标识,用于hash、相等
underlyingQueue: DispatchQueue 内部异步操作的串行队列
serializationQueue: DispatchQueue 序列化使用的队列
eventMonitor: EventMonitor? 事件监控
interceptor: RequestInterceptor? 拦截器(重试器、适配器)
delegate: RequestDelegate?

可变状态部分

通过结构体MutableState封装,包括进度、重定向、缓存、cURL、响应序列化、凭证、请求、task、metrics、重试次数、错误。

1
let protectedMutableState: Protector<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
struct MutableState {
/// State of the `Request`.
var state: State = .initialized
/// `ProgressHandler` and `DispatchQueue` provided for upload progress callbacks.
var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// `ProgressHandler` and `DispatchQueue` provided for download progress callbacks.
var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)?
/// `RedirectHandler` provided for to handle request redirection.
var redirectHandler: RedirectHandler?
/// `CachedResponseHandler` provided to handle response caching.
var cachedResponseHandler: CachedResponseHandler?
/// Closure called when the `Request` is able to create a cURL description of itself.
var cURLHandler: ((String) -> Void)?
/// Response serialization closures that handle response parsing.
var responseSerializers: [() -> Void] = []
/// Response serialization completion closures executed once all response serializers are complete.
var responseSerializerCompletions: [() -> Void] = []
/// Whether response serializer processing is finished.
var responseSerializerProcessingFinished = false
/// `URLCredential` used for authentication challenges.
var credential: URLCredential?
/// All `URLRequest`s created by Alamofire on behalf of the `Request`.
var requests: [URLRequest] = []
/// All `URLSessionTask`s created by Alamofire on behalf of the `Request`.
var tasks: [URLSessionTask] = []
/// All `URLSessionTaskMetrics` values gathered by Alamofire on behalf of the `Request`. Should correspond
/// exactly the the `tasks` created.
var metrics: [URLSessionTaskMetrics] = []
/// Number of times any retriers provided retried the `Request`.
var retryCount = 0
/// Final `AFError` for the `Request`, whether from various internal Alamofire calls or as a result of a `task`.
var error: AFError?
}

内部结构体MutableState 封装可变状态,可能被外部访问

进度部分

包括进度对象和进度处理器

重定向、缓存

response

返回 lastTask?.response as? HTTPURLResponse

task

数组存储着task

下面是功能部分

内部功能

一 、didFailToCreateURLRequest

didFailToCreateURLRequest —retryOrFinish – 调用delegate的retryResult—传递的block内部有finish– processNextResponseSerializer– 找出下一个序列化Hander在serializationQueue队列中执行,如果没有下一个句柄,表示序列化完成执行完成序列化Hander responseSerializerCompletions –> cleanup

didCompleteTask 也是调用 retryOrFinish函数

验证响应

实现在Validation文件中,验证response code、 response mime type 包含在request accept type中

Protector

线程安全的设计思想,定义一个Protector的类,类中有一个锁,需要加锁操作放在block中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
UnfairLock 
unfairLock: os_unfair_lock_t 锁对象
aroud 输入无参闭包,加锁执行,返回闭包结果

func around<T>(_ closure: () -> T) -> T {
lock();
defer {
unlock()
}
return closure()
}


Protector
let lock = UnfairLock()
var value: T
directValue 获取加锁对象
read 读保护资源的操作 ,入参block(带参数) ->封装(非无参数的block)->调用锁的aroud方法
write 写保护资源的操作

好处:

  1. 不用每个受保护资源都写加锁解锁代码。
  2. 泛型使Protector能容纳任何类型。

session

  1. 创建和管理request
  2. 提供了request的基本功能:队列、拦截、信任管理、缓存响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
session: URLSession  创建task使用的session
delegate: SessionDelegate 处理URLSessionDelegate的代理,并与Request交互
rootQueue: DispatchQueue 内部回调、状态更新的队列,必须是串行队列
startRequestsImmediately: Bool 创建request后,是否立即调用resume
requestQueue: DispatchQueue 可以异步创建请求,默认使用rootQueue
serializationQueue: DispatchQueue 解析响应使用的队列
interceptor: RequestInterceptor? 包括重试、适配器
serverTrustManager: ServerTrustManager? 评估信任挑战、提供证书、公钥
redirectHandler: RedirectHandler? 提供定制化重定向
cachedResponseHandler: CachedResponseHandler? 响应缓存管理
eventMonitor: CompositeEventMonitor session事件、请求事件的监控
defaultEventMonitors: [EventMonitor] 默认的通知类型监控
requestTaskMap = RequestTaskMap() request和task的映射
activeRequests: Set<Request> 激活状态的请求

EventMonitor : 包括session的事件和request生命周期中的事件

SessionDelegate :执行URLSessionDelegate的代理

RequestTaskMap

存储请求和tast的双向映射,两个字典 ,下标操作的新值未空是删除功能

1
2
3
4
5
6
7
8
9
10
11
12
13
SessionDelegate
fileManager
处理下载文件时候使用
stateProvider
serverTrustManager
ServerTrustManager类型
管理host ServerTrustEvaluating映射
redirectHandler
cachedResponseHandler

eventMonitor
包括session的事件和request生命周期中的事件
queue

Extended命名作用域

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
extension Array: AlamofireExtended {}
public extension AlamofireExtension where ExtendedType == [SecCertificate] {

var data: [Data] {
return type.map { SecCertificateCopyData($0) as Data }
}
var publicKeys: [SecKey] {
return type.compactMap { $0.af.publicKey }
}
}

public struct AlamofireExtension<ExtendedType> {
let type: ExtendedType
}


public protocol AlamofireExtended {
static var af: AlamofireExtension<ExtendedType>.Type { get set }
}

public extension AlamofireExtended {
static var af: AlamofireExtension<Self>.Type {
get { return AlamofireExtension<Self>.self}
set {}
}
}

声明Array准守AlamofireExtended协议, AlamofireExtended协议中有一个af属性,类型是AlamofireExtension结构体类型。

也就是说如果让Array准守AlamofireExtended协议,即Array中存在名为af计算属性
充当命名空间的作用。

如果想给Array扩展功能,让Array遵守AlamofireExtended,然后给 AlamofireExtension添加扩展功能,通过type成员找到原始期望扩展的类Array。

实际上就是加了个中间层。把系统类的扩展转移到了AlamofireExtension中。

1
2
3
4
5
6
7
8
9
10
Array : AlamofireExtended 
|
|
af属性:AlamofireExtension<>
|
|
type:被扩展的类型
|
|
<-------AlamofireExtension通过type可以直接找到Array本身
1
AlamofireExtension where ExtendedType: Array //只要扩展的是array才能调用的方法

下面是使用方法的理解“

1
2
3
4
5
6
7
8
9
10
11
certificates:[SecCertificate]
certificates.af.publicKeys

extension Array: AlamofireExtended {}
public extension AlamofireExtension where ExtendedType == [SecCertificate] {

/// 枚举证书,获取公钥
var publicKeys: [SecKey] {
return type.compactMap { $0.af.publicKey }
}
}

学习到的知识

OptionSet

OptionSet可以描述位集,每一位表示集合中的一个成员,该协议可以做一些结合的运算。协议有一个rawValue、一些选项。其中选项的值未1、2、4、8 等。以使每个位表示一个选项。

1
2
3
4
5
6
7
8
9
10
11
struct ShippingOptions: OptionSet {
let rawValue: Int

static let nextDay = ShippingOptions(rawValue: 1 << 0)
static let secondDay = ShippingOptions(rawValue: 1 << 1)
static let priority = ShippingOptions(rawValue: 1 << 2)
static let standard = ShippingOptions(rawValue: 1 << 3)

static let express: ShippingOptions = [.nextDay, .secondDay]
static let all: ShippingOptions = [.express, .priority, .standard]
}

感想:

  1. 相关的两个成员属性使用元组表示,可以减少属性个数,便于管理
  2. 只要有几种可选的处理方式,就使用枚举。枚举应用非常多
  3. 函数式编程,消费掉一个参数,生成新的block。