上一篇我們主要說了一下
Alamofire
中對一個(gè)普通的DataRequest
的響應(yīng)序列化的步驟。這次我們針對Requset
的一個(gè)過程簡要分析下
首先我們看下一個(gè)普通的請求的流程經(jīng)過了哪些步驟
之前分析過Alamofire
中的靜態(tài)方法都是調(diào)用SessionManager
里面的方法蒋川,SessionManager
里的default
存放著默認(rèn)的session
牲芋,而SessionDelegate
則實(shí)現(xiàn)了session
的代理。
private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
session.serverTrustPolicyManager = serverTrustPolicyManager
///這里設(shè)置了代理
delegate.sessionManager = self
delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
}
}
再來看看SessionManager
里面
首先聲明了許多閉包,如果你想自己定義你的接收響應(yīng)的邏輯你可以實(shí)現(xiàn)這些閉包
// MARK: URLSessionDelegate Overrides
/// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`.
open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?
/// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.
open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
再來看看里面代理方法的實(shí)現(xiàn)
/// Tells the delegate that the data task has received some of the expected data.
///
/// - parameter session: The session containing the data task that provided data.
/// - parameter dataTask: The data task that provided data.
/// - parameter data: A data object containing the transferred data.
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
///如果實(shí)現(xiàn)了閉包缸浦,則通過閉包傳遞數(shù)據(jù)
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {
///否則通過保存的[task:request]來獲取到request夕冲,調(diào)用其taskDelegate實(shí)例對象的方法,將數(shù)據(jù)傳遞給了TaskDelegate
delegate.urlSession(session, dataTask: dataTask, didReceive: data)
}
}
可以看到將數(shù)據(jù)傳遞到了TaskDelegate
里裂逐,再來看下TaskDelegate
是怎么處理的
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
///獲取響應(yīng)時(shí)間
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
///如果實(shí)現(xiàn)了閉包則通過閉包傳遞出去
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else {
if let dataStream = dataStream {
///如果實(shí)現(xiàn)了request的stream方法歹鱼,則這里將數(shù)據(jù)通過閉包傳遞
dataStream(data)
} else {
///否則存儲(chǔ)數(shù)據(jù)
mutableData.append(data)
}
///計(jì)算此處請求返回?cái)?shù)據(jù)的一個(gè)進(jìn)度
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) }
}
}
}
我們可以看到,針對一個(gè)普通的Data
請求的話卜高,這里的data
就保存了返回的響應(yīng)數(shù)據(jù)弥姻。
override var data: Data? {
if dataStream != nil {
return nil
} else {
return mutableData
}
}
所以后面在序列化返回?cái)?shù)據(jù)的時(shí)候我們可以看到
這里的data就是獲取的request.delegate.data
var dataResponse = DataResponse<T.SerializedObject>(
request: self.request,
response: self.response,
data: self.delegate.data,
result: result,
timeline: self.timeline
)
總的來說,一次普通的請求流程是
- 獲取
URLRequest
- 獲取
URLSessionTask
-
SessionDelegate
接受到代理回調(diào)傳遞給TaskDelegate,TaskDelegate
進(jìn)行處理并保存在自己的屬性里
分步驟詳細(xì)解析
我們還是從最基礎(chǔ)的DataRequest的一個(gè)方法來逐行進(jìn)行分析
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)
}
}
這里通過傳遞一個(gè)URLRequestConvertible
類型的參數(shù)來開始一個(gè)請求
- 通過
URLRequestConvertible
獲取URLRequest
URLRequestConvertible
是一個(gè)協(xié)議篙悯,只有一個(gè)asURLRequest
的方法蚁阳,所以我們知道,你可以傳任意類型哪怕是一個(gè)Pig
的Class
類,只要實(shí)現(xiàn)這個(gè)協(xié)議方法能夠返回URLRequest
即可鸽照,從這里我們可以看到但凡是后綴是Convertible
的協(xié)議都是類似于這樣的便利方法螺捐,就像我們前面分析過的URLConvertible
一樣
-
通過
TaskConvertible
獲取到URLSessionTask
且對urlRequest
進(jìn)行自定義加工-
通過
TaskConvertible
獲取到URLSessionTask
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
這里的
originalTask
類型其實(shí)是DataRequest
的結(jié)構(gòu)體Requestable
的一個(gè)實(shí)例初始化需要傳入urlRequest
,而這個(gè)結(jié)構(gòu)體遵守了協(xié)議TaskConvertible
矮燎,所以我們知道這里可以獲取到URLSessionTask
-
對
urlRequest
進(jìn)行自定義加工在協(xié)議
TaskConvertible
的方法聲明我們看到傳遞了一個(gè)RequestAdapter
的參數(shù)定血,且在結(jié)構(gòu)體Requestable
的協(xié)議實(shí)現(xiàn)內(nèi)我們可以看到這行let urlRequest = try self.urlRequest.adapt(using: adapter)
點(diǎn)擊這里
self.urlRequest
的adapt
方法func adapt(using adapter: RequestAdapter?) throws -> URLRequest { guard let adapter = adapter else { return self } return try adapter.adapt(self) }
是不是繞暈了?诞外?澜沟?哈哈,只能說作者封裝的太仔細(xì)了
其實(shí)這里的
RequestAdapter
協(xié)議就是專門對URLRequest
加工的一個(gè)協(xié)議峡谊,從它的協(xié)議聲明方法可以看出茫虽。 -
返回
URLSessionTask
許多人可能對最后的返回覺得很奇怪
return queue.sync { session.dataTask(with: urlRequest) }
這里返回的是
URLSessionTask
么?既们?點(diǎn)擊這個(gè)sync方法你就可以看到了public func sync<T>(execute work: () throws -> T) rethrows -> T
最后返回的是一個(gè)泛型函數(shù)濒析,而這個(gè)泛型函數(shù)返回的結(jié)果就是函數(shù)參數(shù)
() throws -> T
返回的值,而session.dataTask(with: urlRequest)
返回的是URLSessionTask
-
-
對
request
進(jìn)行包裝let request = DataRequest(session: session, requestTask: .data(originalTask, task))
這里調(diào)用的是
DataRequest
父類Request
的init
方法啥纸,其第三個(gè)參數(shù)requestTask
是一個(gè)枚舉類型号杏,用來對request
進(jìn)行分類并關(guān)聯(lián)值的,在這個(gè)init
方法里面我們可以看到case .data(let originalTask, let task): taskDelegate = DataTaskDelegate(task: task) self.originalTask = originalTask
這里用我們之前獲取到的
sessionTask
來初始化DataTaskDelegate
斯棒,而之前我們說了TaskDelegate
以及其子類是我們最終接收Session
響應(yīng)的地方盾致。 -
一個(gè)
request
請求的開始、暫停荣暮、結(jié)束通過上面我們能看到初始化了一個(gè)
DataTaskDelegate
對象庭惜,我們看初始化方法init(task: URLSessionTask?) { _task = task self.queue = { let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 1 operationQueue.isSuspended = true operationQueue.qualityOfService = .utility return operationQueue }() }
一個(gè)
request
對應(yīng)著一個(gè)TaskDelegate
對象,我們再來看Request
中的resume()
渠驼、suspend()
蜈块、cancel()
方法本質(zhì)上都是控制taskDelegate
的task
對象鉴腻。 -
TaskDelegate
的queue
前面我們可以看到通過
Request
獲得URLSessionTask
,然后執(zhí)行任務(wù)。而這些任務(wù)是在SessionManager
的一個(gè)queue
這個(gè)隊(duì)列里同步進(jìn)行的百揭。這個(gè)queue
是初始化SessionManager
時(shí)候用uuid
生成的一個(gè)不會(huì)重復(fù)的隊(duì)列let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString)
所以所有的網(wǎng)絡(luò)請求爽哎,如果我們用的是同一個(gè)
session
的話,那么這些請求雖然是在后臺執(zhí)行的器一,但是是同步的课锌。所以有時(shí)同時(shí)處理多個(gè)請求時(shí),我們可以采用多個(gè)session
祈秕。而
TaskDelegate
里也有一個(gè)queue
渺贤,/// The serial operation queue used to execute all operations after the task completes. open let queue: OperationQueue
這是OperationQueue類型(不熟悉的可以先了解下),從注釋來看這是當(dāng)任務(wù)執(zhí)行完成后才會(huì)開始執(zhí)行任務(wù)的一條隊(duì)列请毛。
在此文件的
didCompleteWithError
方法里我們可以看到queue.isSuspended = false
,所以這是當(dāng)URLSessionTask
完成之后志鞍,此queue
才開始執(zhí)行,且此隊(duì)列添加的第一個(gè)任務(wù)就是在Request的初始化方法里的delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
結(jié)合之前在
didCompleteWithError
啟動(dòng)隊(duì)列方仿,所以第一個(gè)任務(wù)就是獲取該請求的結(jié)束時(shí)間固棚,后面的響應(yīng)處理在前面的一篇文章中可以看到。
單純的技術(shù)分析仙蚜,也沒啥圖此洲。如果這都能從頭看到尾的話,我佩服你委粉。哈哈呜师。
這次簡單通過一個(gè)
DataRequest
來分析了下請求的一個(gè)過程,后面還會(huì)寫一篇文章來分析下別的類型的Request
的設(shè)計(jì)思路和我對于Alamofire
的一篇最終總結(jié)吧贾节。希望能學(xué)習(xí)到作者的代碼設(shè)計(jì)風(fēng)格汁汗。
最終
太輕易得到的往往都不會(huì)去珍惜,真正失去了卻又后悔莫及栗涂。
聯(lián)系方式
- GitHub: 大貓傳說中的gitHud地址
- 郵箱: 1030472953@qq.com