响应与解析由两个核心模块组成:swift
分为两种响应:api
使用场景:
在使用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> 复制代码
封装响应头, 响应数据, 以及响应对应的请求, 同时定义泛型Success与Error, 用来将响应数据或者错误序列化为对应类型, 扩展了一大堆方法来对响应数据与错误进行变换
只用来封装DataRequest跟UploadRequest的响应markdown
/// 请求
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
}
复制代码
由于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))
}
}
复制代码
跟上面的DataResponse相似, 用来封装响应, 不过只用来封装DownloadRequest的响应, 由于须要封装文件相关的数据,因此属性多了下载文件相关的属性app
对比DataResponse多了两个属性:async
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描述,以及四个类型变换的方法,基本上一毛同样,就再也不赘述
在两个Response实现DebugString协议时,使用了两个辅助类型:
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()) """
}
}
复制代码
extension String {
fileprivate func indentingNewlines(by spaceCount: Int = 4) -> String {
let spaces = String(repeating: " ", count: spaceCount)
return replacingOccurrences(of: "\n", with: "\n\(spaces)")
}
}
复制代码
Alamofire的一个核心为Session+Request及其子类,管理Session,建立URLRequest,发送URLSessionTask,管理Request与Task的关联,处理请求中的各个事件以及错误处理。当请求完成时,须要对响应数据进行解析,默承认以解析为JSON,String,Decodable等格式,也能够本身实现接口把响应数据解析为其余接口。所以另一个核心就是ResponseSerialization响应解析。整个网络请求的流程中,核心就两点:1.发送请求,2.处理请求
很是简单,就一个泛型序列化数据类型,一个简单的序列化方法,分为Data与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
}
复制代码
将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 }
}
复制代码
协议很简单,就一个方法,入参出参均为Data,实现对象能够对入参Data进行预处理,执行增删改查操做后,返回处理后的Data,再继续进行解析,方法容许抛出异常,抛出异常时,上层会catch异常并封装成AFError返回
/// 用来预处理Data的协议, Alamofire有两个默认实现
public protocol DataPreprocessor {
/// 出入参均为Data, 容许抛出异常, 抛出异常时封装为AFError返回
func preprocess(_ data: Data) throws -> Data
}
复制代码
Alamofire实现了两个预处理器struct,权限为public,能够直接使用
没作任何处理,只是把Data原样传递回去,用来在实现ResponseSerializer协议时,做为默认的预处理器使用
/// 默认透传处理器, 不作任何处理
public struct PassthroughPreprocessor: DataPreprocessor {
public init() {}
public func preprocess(_ data: Data) throws -> Data { data }
}
复制代码
去掉数据前缀的)]}',\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添加了三个属性的默认实现,而且添加了三个快捷方法来判断请求与相应是否容许响应数据为空
/// 扩展协议, 给三个属性添加默认实现
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)
}
}
复制代码
当某个序列化器,即实现了Data序列化接口以及Download序列化接口,那么能够把Download序列化的行为看作:
所以就能够对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
}
}
}
复制代码
由于原数据就是Data或者fileurl类型,所以就没有再专门定义序列化器,而是直接对两种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
}
}
复制代码
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
}
}
复制代码
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)
}
}
复制代码
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)
}
}
复制代码
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)
}
}
复制代码
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)
}
}
复制代码
由于Decodable是协议类型,因此稍微有一丢丢复杂
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)
}
}
复制代码
上面的相应数据来自于DataRequest与DownloadRequest,请求均为一次性请求完成,而DataStreamRequest的响应比较特殊,会持续收到Data数据,所以在序列化DataStreamResponse时,只须要对每一个收到的Data数据进行解析便可,相对上面两种简单一点
同上面同样,也是采用协议来解耦。序列化协议也很简单,含有一个泛型的结果数据类型,以及一个序列化方法,该方法只用解析Data,不用解析Request与Response。
public protocol DataStreamSerializer {
/// 序列化结果泛型
associatedtype SerializedObject
/// 序列化方法
func serialize(_ data: Data) throws -> SerializedObject
}
复制代码
Alamofire为StreamRequest定义了3中内置序列化器,添加了4中序列化方法。
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))
}
}
}
复制代码
public struct PassthroughStreamSerializer: DataStreamSerializer {
public func serialize(_ data: Data) throws -> Data { data }
}
复制代码
public struct StringStreamSerializer: DataStreamSerializer {
public func serialize(_ data: Data) throws -> String {
String(decoding: data, as: UTF8.self)
}
}
复制代码
每一个添加个Request的response***方法,本质上都是为Request添加了一个闭包,每次收到数据后,Request都会调用该闭包处理数据,不一样于上面Data于Download请求的闭包只会调用一次,DataStream添加的闭包类型被定义为别名Handler,该闭包的入参为Stream结构体,每一个Stream表明数据流中的一个数据单元,能够表示数据事件,或者完成事件。随着请求不断执行,Handler会被不断调用,所有解析完成后,会对该Handler执行完成处理
@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
}
复制代码
总体逻辑与上面普通处理相似,多了数据解析的步骤,以及通知监听器
@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
}
复制代码
@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()
}
}
复制代码
既然已经定义了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>,绝对不会出错。
@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添加了两个核心闭包:
涉及到各类闭包嵌套,并且加上swift的尾随闭包写法,看起来很难,下一节详细总结下。。。
以上纯属我的理解,不免有误,如发现有错误的地方,欢迎评论指出,将第一时间修改,很是感谢~