概述
Alamofire
跟AFNetworking的功能差不多,都是對URLSession的封裝借尿,對上層提供易用的網絡請求接口刨晴。Alamofire
和AFNetworking分別是Swift和OC的實現(xiàn)版本。目前路翻,這兩個網絡封裝庫的關注度和使用率非常高狈癞,代碼質量也相當不錯。本文想通過對
Alamofire
源碼的簡單分析茂契,了解其基本框架和設計思路蝶桶。源碼鏈接:Alamofire
一個GET請求的源碼分析
- 從最簡單的Get請求入手,分析
Alamofire
的代碼掉冶。一個請求流程真竖,可以分為請求發(fā)送流程和請求響應流程,下文將從這兩個流程展開分析厌小。
// Get請求的調用方式
Alamofire.request("https://httpbin.org/get").responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
請求發(fā)送流程
-
Alamofire.Swift
可以認為Alamofire
一些對外接口的包裝(Facade API)恢共。
Alamofire.request
實際上是調用了SessionManager.request
。
// 調用request方法
/// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of a URL based on the specified `urlRequest`.
@discardableResult
public func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
return SessionManager.default.request(urlRequest)
}
- 在
SessionManager.request
璧亚,Request
被組裝創(chuàng)建讨韭,并加到發(fā)送隊列中,然后等待一系列的響應事件癣蟋。而SessionManager
主要職責是管理發(fā)送隊列透硝,組裝請求消息,設置Session相關的配置疯搅,設置工作線程等濒生。
// 創(chuàng)建request對象,并開始發(fā)送
/// Creates a `DataRequest` to retrieve the contents of a URL based on the specified `urlRequest`.
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
var originalRequest: URLRequest?
do {
originalRequest = try urlRequest.asURLRequest()
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
delegate[task] = request
if startRequestsImmediately { request.resume() }
return request
} catch {
return request(originalRequest, failedWith: error)
}
}
- 接著幔欧,通過
Request.responseJSON
設置JSON響應回調的處理方法罪治。
// 設置回調
/// Adds a handler to be called once the request has finished.
@discardableResult
public func responseJSON(
queue: DispatchQueue? = nil,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (DataResponse<Any>) -> Void)
-> Self
{
return response(
queue: queue,
responseSerializer: DataRequest.jsonResponseSerializer(options: options),
completionHandler: completionHandler
)
}
-
Request.responseJSON
實際上是調用Request.response
,將回調添加到Request.delegate.queue
琐馆,然后等待響應事件规阀。
/// Adds a handler to be called once the request has finished.
@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
}
- 至此恒序,發(fā)送流程完成瘦麸,接著就等待響應事件。
請求響應流程
一個請求的響應事件會有多個歧胁,并按循序上報滋饲,例如以下幾個主要事件厉碟,
HTTPS鑒權事件
func urlSession(_ session: URLSession,task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
收到Response響應頭事件
func urlSession(_ session: URLSession,dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)
收到Response Body數(shù)據事件
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
響應流程完成事件
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
本文以最后一個響應流程完成事件為例,梳理下整個響應流程屠缭。
首先箍鼓,
SessionDelegate
會收到由URLSession.delegate
上報的urlSession:task:didCompleteWithError
,根據task
找到URLSessionTask
并通過其delegate
上報事件給TaskDelegate
呵曹。
/// Tells the delegate that the task finished transferring data.
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
/// Executed after it is determined that the request is not going to be retried
let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
guard let strongSelf = self else { return }
if let taskDidComplete = strongSelf.taskDidComplete {
taskDidComplete(session, task, error)
} else if let delegate = strongSelf[task]?.delegate {
delegate.urlSession(session, task: task, didCompleteWithError: error)
}
NotificationCenter.default.post(
name: Notification.Name.Task.DidComplete,
object: strongSelf,
userInfo: [Notification.Key.Task: task]
)
strongSelf[task] = nil
}
guard let request = self[task], let sessionManager = sessionManager else {
completeTask(session, task, error)
return
}
// Run all validations on the request before checking if an error occurred
request.validations.forEach { $0() }
// Determine whether an error has occurred
var error: Error? = error
if let taskDelegate = self[task]?.delegate, taskDelegate.error != nil {
error = taskDelegate.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)
}
}
- 接著款咖,
TaskDelegate
收到該事件后,恢復queue隊列奄喂,按循序執(zhí)行其中的回調铐殃,如ResponseJSON
。
@objc(URLSession:task:didCompleteWithError:)
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let taskDidCompleteWithError = taskDidCompleteWithError {
taskDidCompleteWithError(session, task, error)
} else {
if let error = error {
if self.error == nil { self.error = error }
if
let downloadDelegate = self as? DownloadTaskDelegate,
let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
{
downloadDelegate.resumeData = resumeData
}
}
// queue隊列中的operaion開始按循序執(zhí)行跨新,回調到上層富腊。
queue.isSuspended = false
}
}
其他模塊
除了發(fā)送,響應相關的代碼域帐,
Alamofire
還有許多其他模塊赘被。例如,NetworkReachabilityManager
管理網絡狀態(tài)肖揣。ParameterEncoding
入參編解碼方式民假。ResponseSerialization
響應的反序列化方式。ServerTrustPolicy
HTTPS的鑒權等等龙优。
總結
- 分析得比較簡單阳欲,抱磚引玉。