前言
前面分析了一波Request的整個(gè)流程和源碼,本文是講解到底在項(xiàng)目中如何實(shí)際使用,來滿足對(duì)于網(wǎng)絡(luò)請(qǐng)求的各種需求。
Adapter動(dòng)態(tài)適配
SessionManager.default.adapter = DLAdapter()
SessionManager.default.request(myGetUrlString, method: .get, parameters: ["array":getJsonFromArray(array)])
.response { (response) in
debugPrint(response)
}
class DLAdapter: RequestAdapter{
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
var request = urlRequest
request.setValue("token_value", forHTTPHeaderField: "token");
return request;
}
}
- 實(shí)現(xiàn)
RequestAdapter,實(shí)現(xiàn)adapt方法,在這里面做了設(shè)置請(qǐng)求頭token的操作 -
SessionManager.default.adapter = DLAdapter(),配置了Adapter后,所有的請(qǐng)求,都會(huì)帶上個(gè)這個(gè)請(qǐng)求頭的值 - 還可以實(shí)現(xiàn)重定向功能等等,具體想統(tǒng)一對(duì)
request做什么處理,要看項(xiàng)目的具體需求了
源碼探索
探索里面的源碼實(shí)現(xiàn),我這里是把幾處的源碼都綜合在一處了
open var adapter: RequestAdapter?
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
let urlRequest = try self.urlRequest.adapt(using: adapter)
func adapt(using adapter: RequestAdapter?) throws -> URLRequest {
guard let adapter = adapter else { return self }
return try adapter.adapt(self)
}
public protocol RequestAdapter {
func adapt(_ urlRequest: URLRequest) throws -> URLRequest
}
在創(chuàng)建task的時(shí)候會(huì)傳遞當(dāng)前的adapter,這個(gè)adapter在這里try adapter.adapt(self)會(huì)執(zhí)行,而且這個(gè)adapter找不到具體的實(shí)現(xiàn),它是外界直接傳遞進(jìn)來的,外界傳遞了則使用,外界不傳遞則不使用。
Retrier請(qǐng)求重試
使用方法很簡(jiǎn)單,和上面基本一樣,實(shí)現(xiàn)RequestRetrier協(xié)議里的should方法即可
SessionManager.default.retrier = DLAdapter()
class DLAdapter: RequestAdapter,RequestRetrier{
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
var request = urlRequest
request.setValue("token_value", forHTTPHeaderField: "token");
return request;
}
func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
completion(true,1)
}
}
- 可以在
should方法里根據(jù)條件判斷是返回true還是false,true則表示需要重試 - 在使用的時(shí)候只要設(shè)置
SessionManager.default.retrier即可 - 實(shí)用的地方很多,比如某個(gè)接口需要輪詢重復(fù)查詢,這種情況用上
retrier很方便
源碼探索
找到使用到retrier的方法
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
/// If an error occurred and the retrier is set, asynchronously ask the retrier if the request
/// should be retried. Otherwise, complete the task by notifying the task delegate.
if let retrier = retrier, let error = error {
retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
guard shouldRetry else { completeTask(session, task, error) ; return }
DispatchQueue.utility.after(timeDelay) { [weak self] in
guard let strongSelf = self else { return }
let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false
if retrySucceeded, let task = request.task {
strongSelf[task] = request
return
} else {
completeTask(session, task, error)
}
}
}
} else {
completeTask(session, task, error)
}
}
- 看注釋的說明是,如果錯(cuò)誤發(fā)生并且設(shè)置了
retrier,會(huì)同步詢問request是否需要retrier,沒發(fā)生錯(cuò)誤就通知taskDelegate請(qǐng)求完成。 - 這里面的方法就相當(dāng)于一個(gè)遞歸,如果
retrySucceeded一直為ture,則會(huì)一直調(diào)用下去,所以我們要注意在should方法中要有返回為false的情況,不然會(huì)一直遞歸下去
自定義驗(yàn)證validate
在實(shí)際相關(guān)項(xiàng)目中,我們可能有一些響應(yīng)碼需要特殊處理,這時(shí)候自定義驗(yàn)證就很適合使用了,如果能配上上面的retrier更加好用,返回error后再retrier
SessionManager.default.request(myGetUrlString, method: .get, parameters: ["array":getJsonFromArray(array)])
.response { (response) in
debugPrint(response)
}.validate { (request, response, data) -> Request.ValidationResult in
guard let _ = data else{
return .failure(NSError.init(domain: "test", code: 10089, userInfo: nil))
}
let code = response.statusCode
if code == 404 {
return .failure(NSError.init(domain: "test2", code: 100800, userInfo: nil))
}
return .success
}
這里是自定義了兩個(gè)error,在data為空和statusCode為404的時(shí)候都會(huì)返回自定義的error信息
public func validate(_ validation: @escaping Validation) -> Self {
let validationExecution: () -> Void = { [unowned self] in
if
let response = self.response,
self.delegate.error == nil,
case let .failure(error) = validation(self.request, response, self.delegate.data)
{
self.delegate.error = error
}
}
validations.append(validationExecution)
return self
}
這里是把驗(yàn)證的閉包加到了validations里,然后在請(qǐng)求完成后,會(huì)把validations里的閉包都執(zhí)行一遍
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
// Run all validations on the request before checking if an error occurred
request.validations.forEach { $0() }
}
TimeLine
Alamofire提供了TimeLine時(shí)間線,為了我們開發(fā)的便捷,能夠通過Timeline快速得到這個(gè)請(qǐng)求的時(shí)間數(shù)據(jù),做一些可能需要做的優(yōu)化操作
timeline: Timeline: {
"Request Start Time": 588099247.070,
"Initial Response Time": 588099272.474,
"Request Completed Time": 588099272.475,
"Serialization Completed Time": 588099272.475,
"Latency": 25.404 secs,
"Request Duration": 25.405 secs,
"Serialization Duration": 0.000 secs,
"Total Duration": 25.405 secs
}
請(qǐng)求開始時(shí)間
open func resume() {
if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }
}
添加請(qǐng)求完成時(shí)間記錄
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session
// 省略無關(guān)代碼,方便閱讀
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
}
初始化響應(yīng)時(shí)間
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
}
時(shí)間軸設(shè)置
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()
)
}
初始化記錄時(shí)間以及計(jì)算時(shí)間
public init(
requestStartTime: CFAbsoluteTime = 0.0,
initialResponseTime: CFAbsoluteTime = 0.0,
requestCompletedTime: CFAbsoluteTime = 0.0,
serializationCompletedTime: CFAbsoluteTime = 0.0)
{
self.requestStartTime = requestStartTime
self.initialResponseTime = initialResponseTime
self.requestCompletedTime = requestCompletedTime
self.serializationCompletedTime = serializationCompletedTime
self.latency = initialResponseTime - requestStartTime
self.requestDuration = requestCompletedTime - requestStartTime
self.serializationDuration = serializationCompletedTime - requestCompletedTime
self.totalDuration = serializationCompletedTime - requestStartTime
}
Result
在Alamofire請(qǐng)求完數(shù)據(jù)后會(huì)返回一個(gè)response,但是這個(gè)不是我們最終的結(jié)果,還需要進(jìn)行一些處理,才能返回成我們需要的。
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
)
}
return self
}
可以看到這個(gè)result是在經(jīng)過responseSerializer.serializeResponse序列化后返回的,DataResponse
public enum Result<Value> {
case success(Value)
case failure(Error)
// 提供成功還有失敗的校驗(yàn)
public var isSuccess: Bool {... }
public var isFailure: Bool {...}
public var value: Value? {...}
public var error: Error? {... }
}
Result的枚舉值只有success和failure,使用起來非常方便
總結(jié)
以上都是比較實(shí)用的Alamofire開發(fā)技巧,希望大家能熟練使用!