本文通過一個get請求,追蹤代碼流程,來進入到整個框架的學習。
1.創建請求
Alamofire.request("https://httpbin.org/get")
- 通過Alamofire來創建
@discardableResult
public func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
return SessionManager.default.request(
url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers
)
}
- 關鍵字@discardableResult,在方法沒有返回值時不會報出警告
- swift參數是支持默認值的,調用時值傳了一個url參數,繼承URLConvertible協議,用來生成URL類型
- HTTPMethod是一個枚舉類型,這里默認值使用get
- Parameters定義為[String: Any],默認是nil。它的定義使用typealias關鍵字,用來為已經存在的類型重新定義名字的,通過命名,可以使代碼變得更加清晰。HTTPHeaders亦是如此
- Alamofire只是一個入口,內部調用SessionManager來完成創建
@discardableResult
open func request(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil)
-> DataRequest
{
var originalRequest: URLRequest?
do {
originalRequest = try URLRequest(url: url, method: method, headers: headers)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
- 聲明originalRequest變量,類型是URLRequest。Swift里不會自動給變量賦初始值,也就是說變量不會有默認值,所以要求使用變量之前必須要對其初始化,如果沒有初始化就會報錯。這時候可以使用optional類型,也就是后面跟一個"?"。
- 試著創建URLRequest,這里加try是因為asURL可能會拋出異常
- 然后調用ParameterEncoding.swift的方法對參數進行編碼
- 最后進入request方法來生成DataRequest
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)
}
}
- originalTask值是一個結構體,這個結構體繼承TaskConvertible協議。該協議定義了task方法,讓每種不同類型的request實現自己創建task的邏輯。這里創建NSURLSessionDataTask類型task的實現代碼是session.dataTask(with: urlRequest)
- 用session和.data(originalTask, task)創建DataRequest。URLRequest(DataRequest的父類)初始化方法會根據task的不同生成對應的taskDelegate
- 把task和request的關系存到delegate中,調用request的resume方法發出請求,內部會觸發task.resume()方法發請求,最后并返回request
整個過程大致是,調用SessionManager.request()方法,獲取URLRerequest,獲取對應的task,創建DataRequest,發起請求。
2.接收請求
if let request = request as? DataRequest {
request.responseString { response in
requestComplete(response.response, response.result)
}
}
- 這里剛開始可能看不太懂,這是尾隨閉包的寫法。這個閉包是request.responseString方法的最后一個參數。
- 這個閉包會被加入到DataRequest的delegate.queue中。TaskDelegate的queue是一個串行隊列,存放task結束之后需要執行的任務
@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
}
- 最終傳進來的閉包會加入到delegate的queue隊列中,并且這個隊列初始化時設置了isSuspend=true,所以它會在改為false才會執行
- 這個opration里會生成result和response,供回調使用,也就是requestComplete(response.response, response.result)的參數
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {
delegate.urlSession(session, dataTask: dataTask, didReceive: data)
}
}
- SessionDelegate繼承URLSessionDataDelegate,實現請求的各種回調
- 下面的判斷會走到else,前面在delegate存儲過task和delegate,所以這里self[dataTask]會得到之前發請求的request,并且是DataTaskDelegate類型
- 于是執行delegate(DataTaskDelegate)的對應方法
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else {
if let dataStream = dataStream {
dataStream(data)
} else {
mutableData.append(data)
}
let bytesReceived = Int64(data.count)
totalBytesReceived += bytesReceived
let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
progress.totalUnitCount = totalBytesExpected
progress.completedUnitCount = totalBytesReceived
if let progressHandler = progressHandler {
progressHandler.queue.async { progressHandler.closure(self.progress) }
}
}
}
- dataStream為((_ data: Data) -> Void)?類型,mutableData被初始化為Data(),它們都是是DataTaskDelegate的實例變量。這里會走到mutableData.append(data)
- bytesReceived計算接收數據的大小
- totalBytesExpected將可選類型dataTask.response解包,然后獲取expectedContentLength.“??"運算符可以用于判斷變量或常量的數值是否是nil,不為nil則取變量或者常量本身的值,如果是nil則使用后面的值替代
- 判斷是否有progressHandler,這不會調用。因為demo中并沒有傳
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
guard let strongSelf = self else { return }
strongSelf.taskDidComplete?(session, task, error)
strongSelf[task]?.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
}
request.validations.forEach { $0() }
var error: Error? = error
if request.delegate.error != nil {
error = request.delegate.error
}
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)
}
}
- SessionDelegate內實現的回調,表示task已經完成數據傳輸
- completeTask,如果請求不需要重試,就會執行這個閉包
- sessionManager沒有被賦值,所以不會走到第一個判斷里
- validations是[() -> Void] = []一種閉包類型的數組,放一些檢查的方法。$0()表示第一個參數,也就是數組里的每一個值
- 用request.delegate.error取到錯誤,如果設置了retrier并有error,就執行重試的方法。否則執行completeTask
- 在completeTask中,首選判斷taskDidComplete有無值然后執行,然后通過strongSelf[task]得到request并調用其urlSession方法
- 最后發通知并把task置為nil
@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.isSuspended = false
}
}
- 上述代碼 strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error) 的方法實現
- 這里在有錯誤時,對DownloadTaskDelegate做了一些處理。
- queue.isSuspended這里是關鍵,isSuspended設置為false后,回調傳進來operation將會開始執行
- @objc 作用:1,fileprivate 或者 private 保證方法私有 能在同一個類 或者 同一個文件(extension)中訪問這個方法 如果定義為private 那么只能在一個類中訪問 不能在類擴展中訪問;2,允許這個函數在“運行時”通過oc的消息機制調用
open subscript(task: URLSessionTask) -> Request? {
get {
lock.lock() ; defer { lock.unlock() }
return requests[task.taskIdentifier]
}
set {
lock.lock() ; defer { lock.unlock() }
requests[task.taskIdentifier] = newValue
}
}
- 上述代碼strongSelf[task] = nil的實現
- 使用lock,保證賦值是線程安全的
- open關鍵字,訪問控制在權限。在swift3中,fileprivate來顯式的表明,這個元素的訪問權限為文件內私有,即extension也可以訪問到。private則是真正的私有,離開了這個類或者結構體的作用域外面就無法訪問。open在module內可以被override,在被import到其他地方后其他用戶使用的時候不能被override。通過open和public標記區別一個元素在其他module中是只能被訪問還是可以被override
- defer關鍵字,推遲執行,會在return之前執行。記得react cocoa里面oc有寫過一個黑魔法來實現這個方法,swift可以直接用關鍵字解決了
整理一下整個過程,把完成的閉包傳入,然后被加到queue中,請求返回后出發queue執行,最終調用最初傳入的閉包
這篇文章從demo里的Alamofire.request("https://httpbin.org/get")開始分析了整個發送和接收請求的過程,有一個大概流程的概念。后面再去逐個分析每個類