主要通過擴展Request
、DataRequest
和DownloadRequest
將服務(wù)器返回的響應(yīng)序列化成我們想要的數(shù)據(jù)比规。
1. 輔助類型
1) DataResponseSerializerProtocol
和DataResponseSerializer<Value>
// DataResponse序列化器協(xié)議浸赫,所有的DataResponse序列化器必須遵循這個協(xié)議
public protocol DataResponseSerializerProtocol {
// 序列化后的對象類型
associatedtype SerializedObject
// 這個閉包告訴我們?nèi)绾涡蛄谢? var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<SerializedObject> { get }
}
// 通用的DataResponse序列化器
public struct DataResponseSerializer<Value>: DataResponseSerializerProtocol {
// 遵循DataResponseSerializerProtocol協(xié)議
public typealias SerializedObject = Value
// 遵循DataResponseSerializerProtocol協(xié)議
public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>
// 初始化方法
public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>) {
self.serializeResponse = serializeResponse
}
}
2) DownloadResponseSerializerProtocol
和DownloadResponseSerializer<Value>
與上面的兩個類似办斑,大家對照遠嗎自己看下扩灯。
2. Timeline
屬性
通過擴展為Request
添加了timeline屬性牵署。
extension Request {
var timeline: Timeline {
let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent()
let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
return Timeline(
requestStartTime: requestStartTime,
initialResponseTime: initialResponseTime,
requestCompletedTime: requestCompletedTime,
serializationCompletedTime: CFAbsoluteTimeGetCurrent()
)
}
}
3. 為DataRequest
添加默認的序列化方法
這兩個方法都沒有將響應(yīng)結(jié)果序列化成一個具體的類型疚颊。
// 這個方法沒有把響應(yīng)結(jié)果序列化成具體的類型
//
// queue:指定completionHandler在哪個隊列執(zhí)行狈孔,默認在主隊列
// 把completionHandler添加到delegate的隊列,請求完成后執(zhí)行隊列
// 在completionHandler中返回默認的數(shù)據(jù)響應(yīng)DefaultDataResponse(沒有經(jīng)過序列化的)
@discardableResult
public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
delegate.queue.addOperation {
(queue ?? DispatchQueue.main).async {
var dataResponse = DefaultDataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
error: self.delegate.error,
timeline: self.timeline
)
dataResponse.add(self.delegate.metrics)
completionHandler(dataResponse)
}
}
return self
}
// 這個方法需要一個序列化器參數(shù)材义,會把響應(yīng)結(jié)果序列化成序列化器需要的具體類型
//
// queue:指定completionHandler在哪個隊列執(zhí)行均抽,默認在主隊列
// 把completionHandler添加到delegate的隊列,請求完成后執(zhí)行隊列
// 在completionHandler中返回默認的數(shù)據(jù)響應(yīng)DefaultDataResponse(經(jīng)過序列化的)
@discardableResult
public func response<T: DataResponseSerializerProtocol>(
queue: DispatchQueue? = nil,
responseSerializer: T,
completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
-> Self
{
delegate.queue.addOperation {
let result = responseSerializer.serializeResponse(
self.request,
self.response,
self.delegate.data,
self.delegate.error
)
var dataResponse = DataResponse<T.SerializedObject>(
request: self.request,
response: self.response,
data: self.delegate.data,
result: result,
timeline: self.timeline
)
dataResponse.add(self.delegate.metrics)
(queue ?? DispatchQueue.main).async { completionHandler(dataResponse) }
}
return self
}
4. 為DownloadRequest
添加默認的序列化方法
這兩個方法跟上面的兩個類似其掂,不做過多說明油挥。
@discardableResult
public func response(
queue: DispatchQueue? = nil,
completionHandler: @escaping (DefaultDownloadResponse) -> Void)
-> Self
{
// ...
}
@discardableResult
public func response<T: DownloadResponseSerializerProtocol>(
queue: DispatchQueue? = nil,
responseSerializer: T,
completionHandler: @escaping (DownloadResponse<T.SerializedObject>) -> Void)
-> Self
{
// ...
}
5. 把響應(yīng)序列化成Data
extension Request {
// 返回序列化后的結(jié)果
public static func serializeResponseData(response: HTTPURLResponse?, data: Data?, error: Error?) -> Result<Data> {
guard error == nil else { return .failure(error!) }
// 如果返回的狀態(tài)碼是204(沒有數(shù)據(jù)返回)和205(重置數(shù)據(jù)),返回空數(shù)據(jù)
if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(Data()) }
guard let validData = data else {
return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
}
return .success(validData)
}
}
extension DataRequest {
// 創(chuàng)建一個數(shù)據(jù)響應(yīng)序列化器款熬,把響應(yīng)序列化成Data類型
public static func dataResponseSerializer() -> DataResponseSerializer<Data> {
// 這里其實是初始化DataResponseSerializer
// 本來是DataResponseSerializer(serializeResponse: closure)深寥,
// 因為closure是語句中的最后一個closure,所以可以把小括號和serializeResponse省略
return DataResponseSerializer { _, response, data, error in
return Request.serializeResponseData(response: response, data: data, error: error)
}
}
// 使用上面創(chuàng)建的數(shù)據(jù)響應(yīng)序列化器贤牛,把響應(yīng)序列化成Data
@discardableResult
public func responseData(
queue: DispatchQueue? = nil,
completionHandler: @escaping (DataResponse<Data>) -> Void)
-> Self
{
return response(
queue: queue,
responseSerializer: DataRequest.dataResponseSerializer(),
completionHandler: completionHandler
)
}
}
extension DownloadRequest {
// 創(chuàng)建一個下載響應(yīng)序列化器惋鹅,把響應(yīng)序列化成Data類型
public static func dataResponseSerializer() -> DownloadResponseSerializer<Data> {
return DownloadResponseSerializer { _, response, fileURL, error in
guard error == nil else { return .failure(error!) }
guard let fileURL = fileURL else {
return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
}
do {
let data = try Data(contentsOf: fileURL)
return Request.serializeResponseData(response: response, data: data, error: error)
} catch {
return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
}
}
}
// 使用上面創(chuàng)建的下載響應(yīng)序列化器,把響應(yīng)序列化成Data
@discardableResult
public func responseData(
queue: DispatchQueue? = nil,
completionHandler: @escaping (DownloadResponse<Data>) -> Void)
-> Self
{
return response(
queue: queue,
responseSerializer: DownloadRequest.dataResponseSerializer(),
completionHandler: completionHandler
)
}
}
5. 把響應(yīng)序列化成String
& JSON
& Property List
把響應(yīng)序列化成這三種類型的思路殉簸,跟序列化成Data
的思路完全一致闰集,大家可以自己看下,如果有不懂的般卑,歡迎留言武鲁,我會盡力解答。
有任何問題蝠检,歡迎大家留言沐鼠!
歡迎加入我管理的Swift開發(fā)群:536353151
,本群只討論Swift相關(guān)內(nèi)容。
原創(chuàng)文章饲梭,轉(zhuǎn)載請注明出處乘盖。謝謝!