往期导航:
简介
响应与解析由两个核心模块组成:
- Response.swift:
定义了两个泛型结构体:DataResponse与DownloadResponse来封装请求的响应,包括:URLRequest, HTTPURLResponse, 响应原始数据(Data格式),序列化后的数据,请求指标数据。DownloadResponse还包括下载文件url,断点续传数据信息等数据
作用仅仅是封装,以及对序列化后的数据或错误进行了变换操作,用来在请求的完成回调作为参数使用。 - ResponseSerialization.swift
把请求到的数据进行序列化,使用泛型协议来进行隔离,可以自由指定序列化后的数据类型
Alamofire内置了几个序列化类型,可以直接拿来使用,也可以自己实现自己的序列化器
在序列化数据之前,还支持先对原始的Data进行预处理,封装为接口DataPreprocessor,解析器可以持有预处理协议对象,在开始解析data之前,先对data使用预处理器进行预处理之后,再进行解析。
Response请求响应封装:
分为两种响应:
- 普通请求响应(包括DataRequest,UploadRequest)
- 下载请求响应(数据会被保存到本地文件,因此会持有一个文件url,若碰到下载中断,还会暂存已下载的数据供断点续传处理)
使用场景:
在使用Alamofire请求时,请求完成回调里的参数,就是Response对象:
//发送请求,把响应数据解析为JSOn
AF.request("").responseJSON(completionHandler: {
(resp : AFDataResponse<Any>) in
resp.data//原始响应Data数据(Data?类型)
resp.value//序列化后的泛型对象(Any?类型)
resp.error//序列化或者请求出错的错误对象(AFError?类型)
})
定义:
两个结构体都使用泛型封装,泛型为序列化的数据类型以及序列化中出的错误:
public struct DataResponse<Success, Failure: Error>
public struct DownloadResponse<Success, Failure: Error>
//然后对这两个类型进行了泛型包装,把错误封装为AFError,用来在Alamofire请求时返回:
public typealias AFDataResponse<Success> = DataResponse<Success, AFError>
public typealias AFDownloadResponse<Success> = DownloadResponse<Success, AFError>
DataResponse
封装响应头, 响应数据, 以及响应对应的请求, 同时定义泛型Success与Error, 用来将响应数据或者错误序列化为对应类型, 扩展了一大堆方法来对响应数据与错误进行变换
只用来封装DataRequest跟UploadRequest的响应
私有属性以及初始化:
/// 请求
public let request: URLRequest?
/// 响应头
public let response: HTTPURLResponse?
/// 响应原始数据
public let data: Data?
/// 最终的请求指标, 包括请求时间, 重定向次数等
public let metrics: URLSessionTaskMetrics?
/// 序列化响应花的时间
public let serializationDuration: TimeInterval
/// 序列化响应的结果
public let result: Result<Success, Failure>
/// 快速取得序列化的数据(可能为nil)
public var value: Success? { result.success }
/// 快速取得序列化的错误
public var error: Failure? { result.failure }
public init(request: URLRequest?,
response: HTTPURLResponse?,
data: Data?,
metrics: URLSessionTaskMetrics?,
serializationDuration: TimeInterval,
result: Result<Success, Failure>) {
self.request = request
self.response = response
self.data = data
self.metrics = metrics
self.serializationDuration = serializationDuration
self.result = result
}
扩展实现String描述以及debugString描述
因为result属性类型是Result泛型,因此在string描述直接把result的描述返回过去,不管类型是.success还是.failure,都会自动转为对应参数类型的描述
extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible {
/// 转为String时的描述, 直接丢result的描述过去, 不管是成功还是失败
public var description: String {
"\(result)"
}
/// debug时的描述信息
public var debugDescription: String {
guard let urlRequest = request else { return "[Request]: None\n[Result]: \(result)" }
let requestDescription = DebugDescription.description(of: urlRequest)
let responseDescription = response.map { response in
let responseBodyDescription = DebugDescription.description(for: data, headers: response.headers)
return """
\(DebugDescription.description(of: response))
\(responseBodyDescription.indentingNewlines())
"""
} ?? "[Response]: None"
let networkDuration = metrics.map { "\($0.taskInterval.duration)s" } ?? "None"
return """
\(requestDescription)
\(responseDescription)
[Network Duration]: \(networkDuration)
[Serialization Duration]: \(serializationDuration)s
[Result]: \(result)
"""
}
}
扩展添加类型变换
因为持有的result是一个保存了成功数据/错误信息的泛型Result,因此添加了四个变换方法,可以返回一个新的DataResponse,成功错误类型可以变换为其他类型:
extension DataResponse {
/// 1.用一个闭包把原result的Success类型变换为新类型, 闭包transform不允许抛出错误, 不处理Failure情况
public func map<NewSuccess>(_ transform: (Success) -> NewSuccess) -> DataResponse<NewSuccess, Failure> {
DataResponse<NewSuccess, Failure>(request: request,
response: response,
data: data,
metrics: metrics,
serializationDuration: serializationDuration,
result: result.map(transform))
}
/// 2.用一个闭包把原result的Success类型变换成新类型, 闭包可以抛出异常, 抛出异常时, 会封装为Failure返回给上层, 同样不处理原result的Failure情况
public func tryMap<NewSuccess>(_ transform: (Success) throws -> NewSuccess) -> DataResponse<NewSuccess, Error> {
DataResponse<NewSuccess, Error>(request: request,
response: response,
data: data,
metrics: metrics,
serializationDuration: serializationDuration,
result: result.tryMap(transform))
}
/// 3.用闭包把原result的Failure情况变换为新的Failure, 对应上面的map
public func mapError<NewFailure: Error>(_ transform: (Failure) -> NewFailure) -> DataResponse<Success, NewFailure> {
DataResponse<Success, NewFailure>(request: request,
response: response,
data: data,
metrics: metrics,
serializationDuration: serializationDuration,
result: result.mapError(transform))
}
/// 4.用闭包处理原result的Failure情况, 可以抛出异常, 对应上面tryMap
public func tryMapError<NewFailure: Error>(_ transform: (Failure) throws -> NewFailure) -> DataResponse<Success, Error> {
DataResponse<Success, Error>(request: request,
response: response,
data: data,
metrics: metrics,
serializationDuration: serializationDuration,
result: result.tryMapError(transform))
}
}
DownloadResponse
跟上面的DataResponse类似, 用来封装响应, 不过只用来封装DownloadRequest的响应, 因为需要封装文件相关的数据,所以属性多了下载文件相关的属性
属性与初始化
对比DataResponse多了两个属性:
public let request: URLRequest?
public let response: HTTPURLResponse?
/// 下载的文件地址
public let fileURL: URL?
/// 下载被取消时, 已经下载的数据, 用来传给上层决定是否保存用以断点续传
public let resumeData: Data?
public let metrics: URLSessionTaskMetrics?
public let serializationDuration: TimeInterval
public let result: Result<Success, Failure>
public var value: Success? { result.success }
public var error: Failure? { result.failure }
public init(request: URLRequest?,
response: HTTPURLResponse?,
fileURL: URL?,
resumeData: Data?,
metrics: URLSessionTaskMetrics?,
serializationDuration: TimeInterval,
result: Result<Success, Failure>) {
self.request = request
self.response = response
self.fileURL = fileURL
self.resumeData = resumeData
self.metrics = metrics
self.serializationDuration = serializationDuration
self.result = result
}
其他扩展
类似上面的DataResponse,DownloadResponse也有对应的两个扩展,分别用来实现String描述,以及四个类型变换的方法,基本上一毛一样,就不再赘述
debug辅助类型与扩展
在两个Response实现DebugString协议时,使用了两个辅助类型:
- 辅助枚举DebugDescription,没有任何case,只封装了四个静态方法,分别用来输出相关的debug信息,调试时可以使用debugPrint函数或者.debugDescription属性来打印
private enum DebugDescription {
static func description(of request: URLRequest) -> String {
let requestSummary = "\(request.httpMethod!) \(request)"
let requestHeadersDescription = DebugDescription.description(for: request.headers)
let requestBodyDescription = DebugDescription.description(for: request.httpBody, headers: request.headers)
return """
[Request]: \(requestSummary)
\(requestHeadersDescription.indentingNewlines())
\(requestBodyDescription.indentingNewlines())
"""
}
static func description(of response: HTTPURLResponse) -> String {
"""
[Response]:
[Status Code]: \(response.statusCode)
\(DebugDescription.description(for: response.headers).indentingNewlines())
"""
}
static func description(for headers: HTTPHeaders) -> String {
guard !headers.isEmpty else { return "[Headers]: None" }
let headerDescription = "\(headers.sorted())".indentingNewlines()
return """
[Headers]:
\(headerDescription)
"""
}
static func description(for data: Data?,
headers: HTTPHeaders,
allowingPrintableTypes printableTypes: [String] = ["json", "xml", "text"],
maximumLength: Int = 100_000) -> String {
guard let data = data, !data.isEmpty else { return "[Body]: None" }
guard
data.count <= maximumLength,
printableTypes.compactMap({ headers["Content-Type"]?.contains($0) }).contains(true)
else { return "[Body]: \(data.count) bytes" }
return """
[Body]:
\(String(decoding: data, as: UTF8.self)
.trimmingCharacters(in: .whitespacesAndNewlines)
.indentingNewlines())
"""
}
}
- 扩展String把普通换行变成带有缩进的换行,简单的替换
extension String {
fileprivate func indentingNewlines(by spaceCount: Int = 4) -> String {
let spaces = String(repeating: " ", count: spaceCount)
return replacingOccurrences(of: "\n", with: "\n\(spaces)")
}
}
ResponseSerialization响应序列化
Alamofire的一个核心为Session+Request及其子类,管理Session,创建URLRequest,发送URLSessionTask,管理Request与Task的关联,处理请求中的各个事件以及错误处理。当请求完成时,需要对响应数据进行解析,默认可以解析为JSON,String,Decodable等格式,也可以自己实现接口把响应数据解析为其他接口。因此另外一个核心就是ResponseSerialization响应解析。整个网络请求的流程中,核心就两点:1.发送请求,2.处理请求
特点:
- 对响应数据序列化使用接口抽象,接口非常简单:入参为:request,task,data,error,出参为泛型序列化后的对象,接口只关心序列化的入参与出参,具体的序列化出来的数据类型与序列化方法由各个序列化器各自实现封装。
- 在序列化前,Alamofire还定义了一个DataPreprocessor接口,用来对原始响应数据线进行预处理操作,入参为Data,出参也为Data,且可以抛出异常。Alamofire内置的几个序列化器都持有了Data预处理器,在开始解析序列化数据前先对Data进行预处理,catch可能产生的错误并抛出,预处理完成后才开始后续的序列化操作
- 在使用Session创建Request之后,其实并没有发送Task,发送task的时机有三个:
- Session.startImmediately = true,创建的request首次调用response***方法添加响应解析回调时,会再添加完成回调之后调用resume发送请求
- Session.startImmediately = true,创建的request为DataStreamRequest,且创建完成后,调用了方法asInputStream()返回InputStream,在创建完IOStream对并绑定之后,就会立刻调用resume发送请求
- Session.startImmediately = false,则创建的request不会自动发送,需要在调用response***方法添加解析回调之后,手动调用request.resume()方法来发送请求
- Alamofire内置了多个序列化器,每个序列化器都有DataResponse与DownResponse两种,每个序列化器定义完成之后都跟着Request的扩展,为Request添加对应的response方法
- 对Request调用.response***方法本质上是添加了一个序列化处理回调,该回调会存在Request的MutableState属性中的responseSerializers回调数组中,当请求完成后,request就会挨个调用序列化回调。因此,可以对创建的一个Request进行多次resonse操作,对同一个请求进行多次解析,得到不同类型的响应数据
- DataStreamResponse的解析处理与DataResponse以及DownloadResponse不同,放在最后单独说明
序列化接口定义
非常简单,就一个泛型序列化数据类型,一个简单的序列化方法,分为Data与Download两种,却别在于:
- Data序列化的原数据类型为Data?,Download序列化的原数据类型为fileURL?
- 对Download的序列化操作,其实也可以看做,先把fileURL用Data读出来,然后用Data序列化方法来处理。因此若一个系列化器同时可以序列化两种task,就可以直接对Download进行实现默认操作(后面会讲)
/// 把请求+响应头+响应Data+错误一起使用接口的方法序列化成泛型响应对象
/// 只供DataResponse使用
public protocol DataResponseSerializerProtocol {
/// 序列化后的数据类型
associatedtype SerializedObject
func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> SerializedObject
}
/// 给DownloadResponse请求使用
public protocol DownloadResponseSerializerProtocol {
/// 序列化后的数据类型
associatedtype SerializedObject
func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> SerializedObject
}
组合序列化接口协议ResponseSerializer
将Data与Download两种序列化协议组合在一起,并加上了Data预处理协议对象,允许空Data的HTTPMethod与响应码。
默认行为下,若返回的响应Data为空,会被当做请求失败处理,但是实际上比如Head请求,没有响应Data。响应码为204(No Content),205(Reset Content)也是只有响应头,没有响应Data。但是不能当做请求失败处理,因此ResponseSerializer添加了两个Set属性来存放允许响应Data为空的HTTPMethod与响应码。
/// 组合协议, 能同时序列化DataResponse与DownloadResponse
public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol {
/// Data预处理器, 用来在序列化之前对Data进行预处理
var dataPreprocessor: DataPreprocessor { get }
/// `HTTPMethod`s for which empty response bodies are considered appropriate.
/// 允许响应data为空的请求Method(默认HEAD请求的响应data为nil)
var emptyRequestMethods: Set<HTTPMethod> { get }
/// 允许响应data为空的错误码(默认[204, 205]的响应码data为nil)
var emptyResponseCodes: Set<Int> { get }
}
响应数据预处理协议DataPreprocessor
协议很简单,就一个方法,入参出参均为Data,实现对象可以对入参Data进行预处理,执行增删改查操作后,返回处理后的Data,再继续进行解析,方法允许抛出异常,抛出异常时,上层会catch异常并封装成AFError返回
/// 用来预处理Data的协议, Alamofire有两个默认实现
public protocol DataPreprocessor {
/// 出入参均为Data, 允许抛出异常, 抛出异常时封装为AFError返回
func preprocess(_ data: Data) throws -> Data
}
Alamofire内置的两个响应数据预处理器
Alamofire实现了两个预处理器struct,权限为public,可以直接使用
透传预处理器PassthroughPreprocessor
没做任何处理,只是把Data原样传递回去,用来在实现ResponseSerializer协议时,作为默认的预处理器使用
/// 默认透传处理器, 不做任何处理
public struct PassthroughPreprocessor: DataPreprocessor {
public init() {}
public func preprocess(_ data: Data) throws -> Data { data }
}
谷歌的XSSI数据预处理器GoogleXSSIPreprocessor
去掉数据前缀的)]}',\n六个字符。只是定义该预处理器,Alamofire中并未使用。
/// 预处理谷歌的XSSI数据, 去掉前6个字符
public struct GoogleXSSIPreprocessor: DataPreprocessor {
public init() {}
public func preprocess(_ data: Data) throws -> Data {
(data.prefix(6) == Data(")]}',\n".utf8)) ? data.dropFirst(6) : data
}
}
扩展ResponseSerializer协议,添加默认实现
为ResponseSerializer添加了三个属性的默认实现,并且添加了三个快捷方法来判断请求与相应是否允许响应数据为空
/// 扩展协议, 给三个属性添加默认实现
extension ResponseSerializer {
/// 默认的Data预处理器为透传处理, 不做任何处理
public static var defaultDataPreprocessor: DataPreprocessor { PassthroughPreprocessor() }
/// 默认允许空Data的Method为HEAD
public static var defaultEmptyRequestMethods: Set<HTTPMethod> { [.head] }
/// 默认允许空Data的状态码为204, 205
public static var defaultEmptyResponseCodes: Set<Int> { [204, 205] }
/// 三个属性的默认实现
public var dataPreprocessor: DataPreprocessor { Self.defaultDataPreprocessor }
public var emptyRequestMethods: Set<HTTPMethod> { Self.defaultEmptyRequestMethods }
public var emptyResponseCodes: Set<Int> { Self.defaultEmptyResponseCodes }
/// 检测request是否允许响应Data为空
/// 使用的是可选类型的map跟flatMap方法, 可选类型的map跟flatMap的方法的参数为数据类型, 返回的类型也是可选类型, 当值不为nil时就会调用闭包, 为nil时直接返回nil
public func requestAllowsEmptyResponseData(_ request: URLRequest?) -> Bool? {
request.flatMap { $0.httpMethod }
.flatMap(HTTPMethod.init)
.map { emptyRequestMethods.contains($0) }
}
/// 检测响应的状态码是否允许Data为空
public func responseAllowsEmptyResponseData(_ response: HTTPURLResponse?) -> Bool? {
response.flatMap { $0.statusCode }
.map { emptyResponseCodes.contains($0) }
}
/// 组合上面两个检测方法
public func emptyResponseAllowed(forRequest request: URLRequest?, response: HTTPURLResponse?) -> Bool {
(requestAllowsEmptyResponseData(request) == true) || (responseAllowsEmptyResponseData(response) == true)
}
}
对Download序列化协议进行扩展添加Data方式的解析实现
当某个序列化器,即实现了Data序列化接口以及Download序列化接口,那么可以把Download序列化的行为看做:
- 先把文件用Data读出来
- 再使用Data的序列化方法来处理 因此就可以对Download解析方法提供默认实现。
要注意的是,直接把整个文件用Data读到内存,要注意文件太大的时候,会爆内存。
/// 给即符合DownloadResponseSerializerProtocol又符合DataResponseSerializerProtocol协议的类型提供默认实现
/// 只要先把数据从文件里读出来就可以作为Data去实现DataResponseSerializerProtocol的序列化方法
/// 注意大文件直接读出来会爆内存
extension DownloadResponseSerializerProtocol where Self: DataResponseSerializerProtocol {
public func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> Self.SerializedObject {
/// 有错直接抛出, 丢给上层去catch
guard error == nil else { throw error! }
/// 文件url为空抛出对应错误
guard let fileURL = fileURL else {
throw AFError.responseSerializationFailed(reason: .inputFileNil)
}
/// 读取Data, catch读取错误并转换抛出
let data: Data
do {
data = try Data(contentsOf: fileURL)
} catch {
throw AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))
}
/// 走DataResponseSerializerProtocol的序列化逻辑, catch错误并抛出
do {
return try serialize(request: request, response: response, data: data, error: error)
} catch {
throw error
}
}
}
定义内置序列化器与添加序列化方法
- Alamofire对Request扩展添加了7种序列化方法,并提供了5种内置序列化器(fileUrl,Data, String, JSON, Decodable),可以直接使用,也可以根据接口自己实现定制的序列化器。
- 每个序列化器都包括定义类型,以及紧跟着定义后面的对DataRequest与DownloadRequest添加的扩展response***方法。
1.原始数据序列化(两种)
因为原数据就是Data或者fileurl类型,因此就没有再专门定义序列化器,而是直接对两种Request添加了扩展序列化响应方法,解析回调也很简单:
- 封装AFResult类型,Success类型为Data?或者URL?类型
- 组装DataResponse,Success类型为1中的AFResult
- 告知事件监听器序列化响应完成
- 告知Request序列化响应完成
extension DataRequest {
/// 普通解析, 只是封装Data
@discardableResult
public func response(queue: DispatchQueue = .main, completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self {
//appendResponseSerializer是一个参数为闭包, 无返回值的方法, 尾随闭包写法第一眼看起来容易疑问
appendResponseSerializer {
// 开始解析响应, 必须在解析队列完成
// 默认不解析, 直接封装下Data
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)
// 回调解析完成
self.responseSerializerDidComplete { queue.async { completionHandler(response) } }
}
}
return self
}
}
extension DownloadRequest {
/// 普通处理下载响应, 下载数据以文件url形式回调处理, 文件url为可选类型
@discardableResult
public func response(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDownloadResponse<URL?>) -> Void)
-> Self {
appendResponseSerializer {
// Start work that should be on the serialization queue.
let result = AFResult<URL?>(value: self.fileURL, error: self.error)
// End work that should be on the serialization queue.
self.underlyingQueue.async {
let response = DownloadResponse(request: self.request,
response: self.response,
fileURL: self.fileURL,
resumeData: self.resumeData,
metrics: self.metrics,
serializationDuration: 0,
result: result)
self.eventMonitor?.request(self, didParseResponse: response)
self.responseSerializerDidComplete { queue.async { completionHandler(response) } }
}
}
return self
}
}
2.使用泛型序列化协议对象来处理响应(两种)
- 分别对应两种响应,这个响应处理方法是最基本的处理方法,下面的几个都是具现化了对应的序列化协议对象来调用该方法,如果使用自己实现的序列化器,也可以使用这个方法来序列化数据,而不需要自己专门写序列化方法。
- 使用序列化协议对象进行处理数据时,需要在Request的serializationQueue队列中执行并计算处理数据所花时间,处理数据完成后,回到underlyingQueue队列进行后续操作
- 序列化时接受的数据可能直接有错误(请求错误),也可能序列化过程中出现错误,若原数据处理完成后的结果为failure,就开始走重试逻辑
- 最后执行完成相关回调
extension DataRequest {
/// 使用自定义解析器解析
@discardableResult
public func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void)
-> Self {
appendResponseSerializer {
// 开始解析响应, 必须在响应解析队列完成, 因为有解析操作, 所以开始计时
let start = ProcessInfo.processInfo.systemUptime
// 用入参解析器解析数据, catch错误并转换成AFError
let result: AFResult<Serializer.SerializedObject> = Result {
try responseSerializer.serialize(request: self.request,
response: self.response,
data: self.data,
error: self.error)
}.mapError { error in
error.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: error)))
}
// 用app启动的时间差值来计算出解析所花时间
let end = ProcessInfo.processInfo.systemUptime
// 解析完成
//回Request内部队列来继续处理
self.underlyingQueue.async {
//组装DataResponse, Success类型为序列化协议中的泛型SerializedObject类型
let response = DataResponse(request: self.request,
response: self.response,
data: self.data,
metrics: self.metrics,
serializationDuration: end - start,
result: result)
//告知监听器
self.eventMonitor?.request(self, didParseResponse: response)
guard let serializerError = result.failure, let delegate = self.delegate else {
// 如果解析成功, 直接走完成逻辑
self.responseSerializerDidComplete { queue.async { completionHandler(response) } }
return
}
// 解析出错, 准备重试
delegate.retryResult(for: self, dueTo: serializerError) { retryResult in
// 是否完成的回调, nil表示要重试
var didComplete: (() -> Void)?
defer {
// 用defer来处理
if let didComplete = didComplete {
self.responseSerializerDidComplete { queue.async { didComplete() } }
}
}
//根据参数retryResult判断是否重试
switch retryResult {
case .doNotRetry:// 不重试, 直接完成
didComplete = { completionHandler(response) }
case let .doNotRetryWithError(retryError):// 不重试, 把error替换掉
// 用新的retryError初始化result
let result: AFResult<Serializer.SerializedObject> = .failure(retryError.asAFError(orFailWith: "Received retryError was not already AFError"))
// 封装新的Response
let response = DataResponse(request: self.request,
response: self.response,
data: self.data,
metrics: self.metrics,
serializationDuration: end - start,
result: result)
didComplete = { completionHandler(response) }
case .retry, .retryWithDelay:// 重试
delegate.retryRequest(self, withDelay: retryResult.delay)
}
}
}
}
return self
}
}
extension DownloadRequest {
/// 使用自定义序列化器来处理下载响应
@discardableResult
public func response<Serializer: DownloadResponseSerializerProtocol>(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDownloadResponse<Serializer.SerializedObject>) -> Void)
-> Self {
appendResponseSerializer {
// 开始序列化结果, 计时
let start = ProcessInfo.processInfo.systemUptime
let result: AFResult<Serializer.SerializedObject> = Result {
try responseSerializer.serializeDownload(request: self.request,
response: self.response,
fileURL: self.fileURL,
error: self.error)
}.mapError { error in
error.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: error)))
}
let end = ProcessInfo.processInfo.systemUptime
// 序列化结果完成
self.underlyingQueue.async {
let response = DownloadResponse(request: self.request,
response: self.response,
fileURL: self.fileURL,
resumeData: self.resumeData,
metrics: self.metrics,
serializationDuration: end - start,
result: result)
self.eventMonitor?.request(self, didParseResponse: response)
guard let serializerError = result.failure, let delegate = self.delegate else {
self.responseSerializerDidComplete { queue.async { completionHandler(response) } }
return
}
// 重试
delegate.retryResult(for: self, dueTo: serializerError) { retryResult in
var didComplete: (() -> Void)?
defer {
if let didComplete = didComplete {
self.responseSerializerDidComplete { queue.async { didComplete() } }
}
}
switch retryResult {
case .doNotRetry:
didComplete = { completionHandler(response) }
case let .doNotRetryWithError(retryError):
let result: AFResult<Serializer.SerializedObject> = .failure(retryError.asAFError(orFailWith: "Received retryError was not already AFError"))
let response = DownloadResponse(request: self.request,
response: self.response,
fileURL: self.fileURL,
resumeData: self.resumeData,
metrics: self.metrics,
serializationDuration: end - start,
result: result)
didComplete = { completionHandler(response) }
case .retry, .retryWithDelay:
delegate.retryRequest(self, withDelay: retryResult.delay)
}
}
}
}
return self
}
}
3.下载文件URL处理(仅DownloadResonse可用)
- 只是一个简单的序列化器,仅DownloadResonse用来处理fileUrl使用
- 因为默认的DownloadResponse中fileUrl为可选类型,可以为nil,因此使用该序列化器后,可将nil的情况过滤,抛出AFError,返回不可选类型的fileURL。
- 扩展DownloadRequest添加了responseURL方法
public struct URLResponseSerializer: DownloadResponseSerializerProtocol {
public init() {}
public func serializeDownload(request: URLRequest?,
response: HTTPURLResponse?,
fileURL: URL?,
error: Error?) throws -> URL {
guard error == nil else { throw error! }
guard let url = fileURL else {
// 文件url为nil的时候, 抛出error
throw AFError.responseSerializationFailed(reason: .inputFileNil)
}
return url
}
}
extension DownloadRequest {
/// 普通处理下载响应, 下载数据以文件url形式回调处理, 文件url一定不为nil
@discardableResult
public func responseURL(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDownloadResponse<URL>) -> Void) -> Self {
response(queue: queue, responseSerializer: URLResponseSerializer(), completionHandler: completionHandler)
}
}
4.Data格式序列化器(两种)
- 定义DataResponseSerializer序列化器实现ResponseSerializer协议并修饰为final,不可继承
- 可预处理Data,处理空Data
- 序列化数据为Data类型
- 扩展DataRequest与DownloadRequest添加responseData序列化方法
public final class DataResponseSerializer: ResponseSerializer {
/// 实现ResponseSerializer协议的三个属性
public let dataPreprocessor: DataPreprocessor
public let emptyResponseCodes: Set<Int>
public let emptyRequestMethods: Set<HTTPMethod>
public init(dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) {
self.dataPreprocessor = dataPreprocessor
self.emptyResponseCodes = emptyResponseCodes
self.emptyRequestMethods = emptyRequestMethods
}
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data {
guard error == nil else { throw error! }
guard var data = data, !data.isEmpty else {
// 如果data空, (包括nil, 空Data), 调用协议扩展的检测是否允许空Data的方法
guard emptyResponseAllowed(forRequest: request, response: response) else {
// 不允许空Data就抛出错误
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
// 允许空Data, 就返回一个空的Data对象
return Data()
}
// 预处理Data
data = try dataPreprocessor.preprocess(data)
// 返回类型为Data
return data
}
}
extension DataRequest {
///扩展DataRequest, 添加解析响应回调
@discardableResult
public func responseData(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<Data>) -> Void) -> Self {
// 调用上面通用的使用序列化协议对象解析的方法
response(queue: queue,
responseSerializer: DataResponseSerializer(dataPreprocessor: dataPreprocessor,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
extension DownloadRequest {
/// 同上
@discardableResult
public func responseData(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDownloadResponse<Data>) -> Void) -> Self {
response(queue: queue,
responseSerializer: DataResponseSerializer(dataPreprocessor: dataPreprocessor,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
5.String格式预处理器
- 定义StringResponseSerializer序列化器实现ResponseSerializer协议并修饰为final,不可继承
- 可指定String编码格式,默认为.isoLatin1。优先级:手动设置 > 服务器返回 > 默认的isoLatin1
- 可预处理Data,处理空Data
- 序列化数据为Data类型
- 扩展DataRequest与DownloadRequest添加responseString序列化方法
public final class StringResponseSerializer: ResponseSerializer {
public let dataPreprocessor: DataPreprocessor
/// string编码格式
public let encoding: String.Encoding?
public let emptyResponseCodes: Set<Int>
public let emptyRequestMethods: Set<HTTPMethod>
public init(dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
encoding: String.Encoding? = nil,
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) {
self.dataPreprocessor = dataPreprocessor
self.encoding = encoding
self.emptyResponseCodes = emptyResponseCodes
self.emptyRequestMethods = emptyRequestMethods
}
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> String {
guard error == nil else { throw error! }
//先检测下空data情况, 抛出异常或者是返回空字符串
guard var data = data, !data.isEmpty else {
guard emptyResponseAllowed(forRequest: request, response: response) else {
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
return ""
}
//预处理Data
data = try dataPreprocessor.preprocess(data)
//string编码格式
var convertedEncoding = encoding
if let encodingName = response?.textEncodingName, convertedEncoding == nil {
// 未指定编码格式, 且服务器有返回编码格式
convertedEncoding = String.Encoding(ianaCharsetName: encodingName)
}
// 实际编码格式: 手动设置 > 服务器返回 > 默认的isoLatin1
let actualEncoding = convertedEncoding ?? .isoLatin1
// 编码, 编码失败抛出错误
guard let string = String(data: data, encoding: actualEncoding) else {
throw AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding))
}
return string
}
}
extension DataRequest {
/// 添加解析方法
@discardableResult
public func responseString(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
encoding: String.Encoding? = nil,
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self {
response(queue: queue,
responseSerializer: StringResponseSerializer(dataPreprocessor: dataPreprocessor,
encoding: encoding,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
extension DownloadRequest {
/// 同上
@discardableResult
public func responseString(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
encoding: String.Encoding? = nil,
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDownloadResponse<String>) -> Void) -> Self {
response(queue: queue,
responseSerializer: StringResponseSerializer(dataPreprocessor: dataPreprocessor,
encoding: encoding,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
6.JOSN格式序列化器(两种)
- 定义JSONResponseSerializer序列化器实现ResponseSerializer协议并修饰为final,不可继承
- 可指定JSON读取格式,默认为.allowFragments
- 使用系统的JSONSerialization解析Data
- 可预处理Data,处理空Data
- 序列化数据为Data类型
- 扩展DataRequest与DownloadRequest添加responseJSON序列化方法
public final class JSONResponseSerializer: ResponseSerializer {
public let dataPreprocessor: DataPreprocessor
public let emptyResponseCodes: Set<Int>
public let emptyRequestMethods: Set<HTTPMethod>
/// JSON读取格式
public let options: JSONSerialization.ReadingOptions
public init(dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
options: JSONSerialization.ReadingOptions = .allowFragments) {
self.dataPreprocessor = dataPreprocessor
self.emptyResponseCodes = emptyResponseCodes
self.emptyRequestMethods = emptyRequestMethods
self.options = options
}
// 实现协议的解析方法
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any {
guard error == nil else { throw error! }
// 判断处理空Data
guard var data = data, !data.isEmpty else {
guard emptyResponseAllowed(forRequest: request, response: response) else {
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
return NSNull()
}
// 预处理
data = try dataPreprocessor.preprocess(data)
do {
// 序列化JSON
return try JSONSerialization.jsonObject(with: data, options: options)
} catch {
// 捕捉抛出错误
throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
}
}
}
extension DataRequest {
/// 添加响应方法
@discardableResult
public func responseJSON(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse<Any>) -> Void) -> Self {
response(queue: queue,
responseSerializer: JSONResponseSerializer(dataPreprocessor: dataPreprocessor,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods,
options: options),
completionHandler: completionHandler)
}
}
extension DownloadRequest {
/// 同上
@discardableResult
public func responseJSON(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDownloadResponse<Any>) -> Void) -> Self {
response(queue: queue,
responseSerializer: JSONResponseSerializer(dataPreprocessor: dataPreprocessor,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods,
options: options),
completionHandler: completionHandler)
}
}
7.Decodable格式序列化器(两种)
因为Decodable是协议类型,所以稍微有一丢丢复杂
- 声明了空数据协议类型EmptyResponse,用一个静态方法emptyValue()来返回空的数据类型
- 声明了Empty结构体,实现了Codable与EmptyResponse协议,可以用来当做默认的EmptyResponse使用(实际上并没有用到,唯一的用处是在使用Encodable协议类型参数初始化StreamRequest时,作为默认空参数使用)
- 声明了DataDecoder解码器协议,用来把Data类型的响应数据解码为Decoable协议类型,因为解码方法与系统的默认的JSONDecoder以及PropertyListDecoder的解码同名,因此只用声明下这两个系统解码器实现DataDecoder协议即可直接拿来用
- 定义DecodableResponseSerializer序列化器实现ResponseSerializer协议并修饰为final,不可继承,并且声明了泛型T实现Decodable协议作为序列化结果类型
- 持有DataDecoder解码器协议属性,用来解码Data,默认为JSONDecoder
- 可预处理Data,处理空Data
- 序列化数据为Data类型
- 扩展DataRequest与DownloadRequest添加responseDecodable序列化方法
public final class DecodableResponseSerializer<T: Decodable>: ResponseSerializer {
public let dataPreprocessor: DataPreprocessor
/// 用来解码的解码器, 默认为系统JSONDecoder解码器
public let decoder: DataDecoder
public let emptyResponseCodes: Set<Int>
public let emptyRequestMethods: Set<HTTPMethod>
public init(dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor,
decoder: DataDecoder = JSONDecoder(),
emptyResponseCodes: Set<Int> = DecodableResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer.defaultEmptyRequestMethods) {
self.dataPreprocessor = dataPreprocessor
self.decoder = decoder
self.emptyResponseCodes = emptyResponseCodes
self.emptyRequestMethods = emptyRequestMethods
}
/// 实现ResponseSerializer协议的解析方法
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
guard error == nil else { throw error! }
// 处理空数据
guard var data = data, !data.isEmpty else {
guard emptyResponseAllowed(forRequest: request, response: response) else {
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
//从解析结果类型T, 获取空数据常量
guard let emptyResponseType = T.self as? EmptyResponse.Type, let emptyValue = emptyResponseType.emptyValue() as? T else {
// 解析结果类型T若不遵循EmptyResponse类型就抛出错误
throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)"))
}
// 返回默认空数据
return emptyValue
}
//预处理Data
data = try dataPreprocessor.preprocess(data)
do {
// 解码Data
return try decoder.decode(T.self, from: data)
} catch {
// 捕捉抛出异常
throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error))
}
}
}
extension DataRequest {
/// 追加
@discardableResult
public func responseDecodable<T: Decodable>(of type: T.Type = T.self,
queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
decoder: DataDecoder = JSONDecoder(),
emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self {
response(queue: queue,
responseSerializer: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor,
decoder: decoder,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
extension DownloadRequest {
/// 同上
@discardableResult
public func responseDecodable<T: Decodable>(of type: T.Type = T.self,
queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
decoder: DataDecoder = JSONDecoder(),
emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDownloadResponse<T>) -> Void) -> Self {
response(queue: queue,
responseSerializer: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor,
decoder: decoder,
emptyResponseCodes: emptyResponseCodes,
emptyRequestMethods: emptyRequestMethods),
completionHandler: completionHandler)
}
}
DataStreamRequest请求响应数据的序列化
上面的相应数据来自于DataRequest与DownloadRequest,请求均为一次性请求完成,而DataStreamRequest的响应比较特殊,会持续收到Data数据,因此在序列化DataStreamResponse时,只需要对每个收到的Data数据进行解析即可,相对上面两种简单一点
序列化协议
同上面一样,也是采用协议来解耦。序列化协议也很简单,含有一个泛型的结果数据类型,以及一个序列化方法,该方法只用解析Data,不用解析Request与Response。
public protocol DataStreamSerializer {
/// 序列化结果泛型
associatedtype SerializedObject
/// 序列化方法
func serialize(_ data: Data) throws -> SerializedObject
}
定义内置序列化器与添加序列化方法
Alamofire为StreamRequest定义了3中内置序列化器,添加了4中序列化方法。
- 相对上面Data与Download请求,少了fileurl以及JSON格式的序列化器
- 序列化器是放在一起定义,序列化方法也是一次性添加,不同于Data与Download请求序列化的定义一个序列化器紧跟着添加序列化方法。
- 因为不需要处理Request与Response,且没有重试逻辑,因此解析器逻辑其实非常简单
1.DecodableStreamSerializer可解码协议类型对象序列化器
- 将Data序列化为符合Decodable协议的泛型对象
- 持有DataDecoder泛型解码器对象,默认解码器为系统JSONDecoder
- 持有预处理器,可以预处理Data
- 解析逻辑类似上面
public struct DecodableStreamSerializer<T: Decodable>: DataStreamSerializer {
/// 解析Data的解析器, 默认为系统的JSONDecoder
public let decoder: DataDecoder
/// Data预处理器
public let dataPreprocessor: DataPreprocessor
public init(decoder: DataDecoder = JSONDecoder(), dataPreprocessor: DataPreprocessor = PassthroughPreprocessor()) {
self.decoder = decoder
self.dataPreprocessor = dataPreprocessor
}
// 解析
public func serialize(_ data: Data) throws -> T {
// 预处理
let processedData = try dataPreprocessor.preprocess(data)
do {
// 解析Data
return try decoder.decode(T.self, from: processedData)
} catch {
// 捕捉异常并抛出
throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error))
}
}
}
2.PassthroughStreamSerializer透传序列化器
- 对data不做任何处理,仅仅是透传
- 作为默认序列化器使用
public struct PassthroughStreamSerializer: DataStreamSerializer {
public func serialize(_ data: Data) throws -> Data { data }
}
3.StringStreamSerializer字符串序列化器
- 把Data使用UTF8解码为string
public struct StringStreamSerializer: DataStreamSerializer {
public func serialize(_ data: Data) throws -> String {
String(decoding: data, as: UTF8.self)
}
}
为DataStreamRequest添加序列化方法
每个添加个Request的response***方法,本质上都是为Request添加了一个闭包,每次收到数据后,Request都会调用该闭包处理数据,不同于上面Data于Download请求的闭包只会调用一次,DataStream添加的闭包类型被定义为别名Handler,该闭包的入参为Stream结构体,每个Stream代表数据流中的一个数据单元,可以表示数据事件,或者完成事件。随着请求不断执行,Handler会被不断调用,全部解析完成后,会对该Handler执行完成处理
1.添加以Data格式处理响应的方法
- 收到数据并没有进行序列化处理,只是简单的执行后续流程
- 会为Request添加一个处理流的回调,保存在Mutable.streams数组中
- 把该回调又封装了一个完成回调,保存在Mutable.enqueuedCompletionEvents数组中,用来在全部数据解析完成之后,发送完成数据单元。
- 为DataStreamRequest添加responseStream方法
@discardableResult
public func responseStream(on queue: DispatchQueue = .main, stream: @escaping Handler<Data, Never>) -> Self {
// 创建解析回调paser, 然后追加到Request的解析回调队列里
let parser = { [unowned self] (data: Data) in
queue.async {
self.capturingError {
// 执行Handle, 捕捉异常
try stream(.init(event: .stream(.success(data)), token: .init(self)))
}
// 更新状态,并检测是否需要完成
self.updateAndCompleteIfPossible()
}
}
// 追加解析回调
$streamMutableState.write { $0.streams.append(parser) }
// 把完成回调追加给Handle
appendStreamCompletion(on: queue, stream: stream)
return self
}
2.添加以使用DataStreamSerializer泛型序列化器处理方法
整体逻辑与上面普通处理类似,多了数据解析的步骤,以及通知监听器
- 解析后的数据为DataStreamSerializer泛型序列化中的数据类型
- 是最基本的解析方法,下面两个解析方法都会使用对应的序列化器实例派发过来调用
- 解析处理需要在serializationQueue队列执行
- 解析完成后会通知eventMonitor事件监听器
- 解析失败会根据automaticallyCancelOnStreamError属性来决定是否取消请求
- 为DataStreamRequest追加responseStream序列化方法
@discardableResult
public func responseStream<Serializer: DataStreamSerializer>(using serializer: Serializer,
on queue: DispatchQueue = .main,
stream: @escaping Handler<Serializer.SerializedObject, AFError>) -> Self {
// 创建parser回调
let parser = { [unowned self] (data: Data) in
self.serializationQueue.async {
// 在解析队列开始解析任务
let result = Result { try serializer.serialize(data) }
.mapError { $0.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: $0))) }
// 解析完成
self.underlyingQueue.async {
self.eventMonitor?.request(self, didParseStream: result)
// 如果解析失败, 且设置了失败取消的话, 取消请求
if result.isFailure, self.automaticallyCancelOnStreamError {
self.cancel()
}
queue.async {
self.capturingError {
try stream(.init(event: .stream(result), token: .init(self)))
}
//更新状态,并检测是否需要完成
self.updateAndCompleteIfPossible()
}
}
}
}
// 添加到回调数组
$streamMutableState.write { $0.streams.append(parser) }
// 追加流完成数据
appendStreamCompletion(on: queue, stream: stream)
return self
}
3.添加解析为String的序列化方法
- 把Data使用UTF8解码为String
- stream处理回调入参类型的错误格式是Never而不是AFError,默认解码为String时,不会失败
- 理论上应该使用上面定义的StringStreamSerializer序列化器,但是实际上,因为解析操作比较简单,且stream处理回调入参类型不同,因此并没有使用StringStreamSerializer来解析,而是直接用类似处理data的写法
- 为DataStreamRequest追加responseStreamString方法
@discardableResult
public func responseStreamString(on queue: DispatchQueue = .main,
stream: @escaping Handler<String, Never>) -> Self {
let parser = { [unowned self] (data: Data) in
self.serializationQueue.async {
// Start work on serialization queue.
let string = String(decoding: data, as: UTF8.self)
// End work on serialization queue.
self.underlyingQueue.async {
self.eventMonitor?.request(self, didParseStream: .success(string))
queue.async {
self.capturingError {
try stream(.init(event: .stream(.success(string)), token: .init(self)))
}
//更新状态,并检测是否需要完成
self.updateAndCompleteIfPossible()
}
}
}
}
$streamMutableState.write { $0.streams.append(parser) }
appendStreamCompletion(on: queue, stream: stream)
return self
}
更新状态以及检测是否解析完成的方法
当每个Stream请求收到Data后,开始准备解析数据,会把对应DataStreamRequest的numberOfExecutingStreams加上所持有的Stream流回调个数,表示这些回调全部进入解析状态,然后每个流解析完成后,都会把numberOfExecutingStreams减1,并在解析完成后检测是否减为0,若numberOfExecutingStreams == 0表示所有回调都已解析完该data,DataStreamRequest就对保存在enqueuedCompletionEvents中的完成回调逐个调用,调用完成后全部移除,而在解析期间如果有添加新的解析回调,解析回调用的完成回调就会先存入enqueuedCompletionEvents中,等待全部流回调处理完成后逐个执行。
private func updateAndCompleteIfPossible() {
$streamMutableState.write { state in
//处理中的流回调减1
state.numberOfExecutingStreams -= 1
guard state.numberOfExecutingStreams == 0, !state.enqueuedCompletionEvents.isEmpty else {
// 若还有流回调在处理,或者没有完成处理回调,就直接返回
return
}
// 全部流回调均已处理完毕,开始处理完成回调
let completionEvents = state.enqueuedCompletionEvents
// 逐个调用
self.underlyingQueue.async { completionEvents.forEach { $0() } }
// 清空保存的完成回调
state.enqueuedCompletionEvents.removeAll()
}
}
3+. 使用StringStreamSerializer序列化器处理响应
既然已经定义了StringStreamSerializer字符串序列化器,那么String解析处理其实可以直接使用这个序列化器处理,而且逻辑更加简单:
//为DataStreamRequest添加一个responseStreamString2解析方法
@discardableResult
public func responseStreamString2(on queue: DispatchQueue = .main,
stream: @escaping Handler<String, AFError>) -> Self {
responseStream(using: StringStreamSerializer(), on: queue, stream: stream)
}
虽然stream处理的Handle闭包的错误参数为AFError,但是该错误其实是在解析出错时抛出的,而StringStreamSerializer解析方法根本不会抛出错误,也就意味着Handler<String, AFError> 等同于Handler<String, Never>,绝对不会出错。
4. 使用DecodableStreamSerializer泛型解析器处理响应
- 使用DecodableStreamSerializer泛型序列化器解析Data
- 为DataStreamRequest添加responseStreamDecodable解析方法
@discardableResult
public func responseStreamDecodable<T: Decodable>(of type: T.Type = T.self,
on queue: DispatchQueue = .main,
using decoder: DataDecoder = JSONDecoder(),
preprocessor: DataPreprocessor = PassthroughPreprocessor(),
stream: @escaping Handler<T, AFError>) -> Self {
responseStream(using: DecodableStreamSerializer<T>(decoder: decoder, dataPreprocessor: preprocessor),
stream: stream)
}
总结
为Request扩展添加response***响应方法,本质上时给Request添加了两个核心闭包:
- 解析闭包:用来解析数据(Data与Download请求只调用一次,Stream请求会调用多次)
- 完成闭包:用来处理解析完成逻辑(Data与Download是在解析闭包中添加,Stream是在添加解析闭包后添加,而且完成比宝会引用解析闭包)
涉及到各种闭包嵌套,而且加上swift的尾随闭包写法,看起来很难,下一节详细总结下。。。
以上纯属个人理解,难免有误,如发现有错误的地方,欢迎评论指出,将第一时间修改,非常感谢~