請(qǐng)求過(guò)程
Alamofire中的靜態(tài)方法都是調(diào)用SessionManager里面的方法,SessionManager的default里存放著默認(rèn)的session,而SessionDelegate則實(shí)現(xiàn)了session的代理。
SessionDelegate類中:
1.聲明了許多閉包,如果你想自定義接收響應(yīng)的邏輯可以實(shí)現(xiàn)閉包
open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?
/// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.
open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
/// Overrides all behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)` and requires the caller to call the `completionHandler`.
open var sessionDidReceiveChallengeWithCompletion: ((URLSession, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?
2.看下回調(diào)的代理方法的實(shí)現(xiàn)
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)
}
}
如果外界實(shí)現(xiàn)閉包dataTaskDidReceiveData,就直接回調(diào)閉包dataTaskDidReceiveData,不再下發(fā)到具體的代理DataTaskDelegate執(zhí)行。
否則將任務(wù)下發(fā)到DataTaskDelegate去執(zhí)行。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) }
}
}
}
Request初探
明白Alamofire中一個(gè)請(qǐng)求的過(guò)程,是非常有必要的。先看下邊的代碼:
SessionManager.default.request(myGetUrlString, method: .get, parameters: ["array":getJsonFromArray(array)])
.response { (response) in
debugPrint(response)
}
上邊的代碼是最簡(jiǎn)單的一個(gè)請(qǐng)求,我們看看Alamofire.request中究竟干了什么?
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)
}
}
1.創(chuàng)建URLRequest
2.encoding是URLEncoding類型的.encoding.encode會(huì)調(diào)用到
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
guard let url = urlRequest.url else {
throw AFError.parameterEncodingFailed(reason: .missingURL)
}
if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
urlComponents.percentEncodedQuery = percentEncodedQuery
urlRequest.url = urlComponents.url
}
} else {
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
}
return urlRequest
}
urlRequest是URLRequestConvertible協(xié)議類型,URLRequestConvertible協(xié)議的目的是對(duì)URLRequest進(jìn)行自定義的轉(zhuǎn)換。
判斷method,如果method是.get, .head, .delete類型,需要urlComponents.percentEncodedQuery進(jìn)行百分號(hào)編碼,并且query(parameters)參數(shù)拼接。
如果是post,需要設(shè)置請(qǐng)求頭application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type,然后拼接參數(shù)query(parameters),將參數(shù)轉(zhuǎn)換為二進(jìn)制并賦值到urlRequest.httpBody
我們看看query(parameters)的實(shí)現(xiàn):
private func query(_ parameters: [String: Any]) -> String {
var components: [(String, String)] = []
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
components += queryComponents(fromKey: key, value: value)
}
return components.map { "\($0)=\($1)" }.joined(separator: "&")
}
(1)將所有參數(shù)的keys按照ASCII碼排序
(2)創(chuàng)建components數(shù)組,遍歷parameters,取出每一對(duì)ket-value
(3)調(diào)用queryComponents(key,value),返回一個(gè)元祖,并添加到數(shù)組components
public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
var components: [(String, String)] = []
if let dictionary = value as? [String: Any] {
for (nestedKey, value) in dictionary {
components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
}
} else if let array = value as? [Any] {
for value in array {
components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value)
}
} else if let value = value as? NSNumber {
if value.isBool {
components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue))))
} else {
components.append((escape(key), escape("\(value)")))
}
} else if let bool = value as? Bool {
components.append((escape(key), escape(boolEncoding.encode(value: bool))))
} else {
components.append((escape(key), escape("\(value)")))
}
return components
}
如果是dictionary和array類型,繼續(xù)遞歸調(diào)用queryComponents,如果是NSNumber,Bool,String類型,將數(shù)據(jù)添加到components。
(4).components.map { "\($0)=\($1)" }轉(zhuǎn)化為key-vaue的字符串?dāng)?shù)組,然后調(diào)用joined(separator: "&"),&作為分隔符,連接成我們需要的數(shù)據(jù)并返回
Request內(nèi)部關(guā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)
}
}
1.首先創(chuàng)建一個(gè)Requestable結(jié)構(gòu)體對(duì)象,使用Requestable創(chuàng)建task。
為什么要有Requestable這個(gè)層,不直接把task·放到DataRequest? (1)我們知道task和request是一一對(duì)應(yīng)的關(guān)系,關(guān)系是平級(jí)的,如果直接把task放到DataRequest`中,體現(xiàn)的是一種歸屬關(guān)系。
(2)降低耦合性。任務(wù)分層,架構(gòu)思路更清晰
2.delegate[task] = request,綁定task和request , 方便SessionDelegate下發(fā)任務(wù),用task直接檢索到request。
delegate[task] = request我們?cè)?code>OC中看到這種寫(xiě)法都是數(shù)組或者字典,而這里的delegate是一個(gè)類。這是Swift的下標(biāo)法。我們看看實(shí)現(xiàn):
var requests: [Int: Request] = [:]
private let lock = NSLock()
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
}
}
類可以重寫(xiě)下標(biāo),支持get,get方法。這種方式SessionDelegate不直接持有Request可以降低耦合。
3.if startRequestsImmediately { request.resume() },滿足startRequestsImmediately,就會(huì)發(fā)起請(qǐng)求。 open var startRequestsImmediately: Bool = true,startRequestsImmediately默認(rèn)會(huì)true。為什么要這么設(shè)計(jì)?而不直接調(diào)用request.resume()。這里是為了讓用戶可以通過(guò)在外界對(duì)startRequestsImmediately控制,而達(dá)到控制請(qǐng)求發(fā)不發(fā)起。
4.Request有許多不同的子類實(shí)現(xiàn)。DataRequest,DownloadRequest,UploadRequest,StreamRequest。這里是任務(wù)細(xì)分。
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
do {
let urlRequest = try self.urlRequest.adapt(using: adapter)
return queue.sync { session.dataTask(with: urlRequest) }
} catch {
throw AdaptError(error: error)
}
}
DataRequest初始化:調(diào)用父類Request的init方法
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
self.session = session
switch requestTask {
case .data(let originalTask, let task):
taskDelegate = DataTaskDelegate(task: task)
self.originalTask = originalTask
case .download(let originalTask, let task):
taskDelegate = DownloadTaskDelegate(task: task)
self.originalTask = originalTask
case .upload(let originalTask, let task):
taskDelegate = UploadTaskDelegate(task: task)
self.originalTask = originalTask
case .stream(let originalTask, let task):
taskDelegate = TaskDelegate(task: task)
self.originalTask = originalTask
}
delegate.error = error
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
}
1.使用枚舉requestTask標(biāo)識(shí)不同的類型。是工廠設(shè)計(jì)模式,根據(jù)用戶傳進(jìn)來(lái)的枚舉標(biāo)識(shí),走不同的初始化。
2.保存相關(guān)信息originalTask(Requestable類型)
requestTask有如下幾種:
enum RequestTask {
case data(TaskConvertible?, URLSessionTask?)
case download(TaskConvertible?, URLSessionTask?)
case upload(TaskConvertible?, URLSessionTask?)
case stream(TaskConvertible?, URLSessionTask?)
}
這里的根據(jù)枚舉類型的不同,會(huì)初始化不同的代理,DataTaskDelegate,DownloadTaskDelegate,UploadTaskDelegate,TaskDelegate。疑問(wèn):為什么已經(jīng)有SessionDelegate,還要有這些代理?這些代理與SessionDelegate是什么關(guān)系?
上面的請(qǐng)求流程我們有提到:
1.SessionDelegate是session的代理,那么所有的代理方法都會(huì)首先來(lái)到SessionDelegate
2.SessionDelegate下發(fā)響應(yīng)到具體的任務(wù)實(shí)現(xiàn)者SessionDelegate,其實(shí)就是整體和局部關(guān)系.
3.所有的響應(yīng)都會(huì)來(lái)到SessionDelegate,如果SessionDelegate將所有的響應(yīng)都自己處理,那將會(huì)很復(fù)雜,混亂.根據(jù)不同的需求將具體實(shí)現(xiàn)下發(fā)到對(duì)應(yīng)的代理中處理,耦合性大大降低,架構(gòu)的分層更加明顯。
如上述請(qǐng)求過(guò)程中提到的:
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可以快速方便的通過(guò)dataTask 獲取到request。然后拿到具體的delegate,如DataTaskDelegate。然后下發(fā)具體的任務(wù),至于DataTaskDelegate中做了什么SessionDelegate根本就不需要知道。
總結(jié):
