你好,我是Emma,今天研究的課題是Alamofire中SessionManager和DataRequest以及task之間的關(guān)系。本篇文檔以
SessionManager.default.request(urlString)
.response { (response) in debugPrint(response) }
為切入點(diǎn)。
1. SessionManager類(lèi)
open class SessionManager {
public static let `default`: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return SessionManager(configuration: configuration)
}()
}
其中的SessionManager.defaultHTTPHeaders指的是什么旧困?
public static let defaultHTTPHeaders: HTTPHeaders = {
let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5"
let acceptLanguage = Locale.preferredLanguages.prefix(6).enumerated().map { index, languageCode in
let quality = 1.0 - (Double(index) * 0.1)
return "\(languageCode);q=\(quality)"
}.joined(separator: ", ")
let userAgent: String = {...}()
return [
"Accept-Encoding": acceptEncoding,
"Accept-Language": acceptLanguage,
"User-Agent": userAgent
]
}()
初始化方法:
open class SessionManager {
public init(
configuration: URLSessionConfiguration = URLSessionConfiguration.default,
//原生和Alomofire之間的代理移交
delegate: SessionDelegate = SessionDelegate(),
serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
//設(shè)置代理這個(gè)類(lèi)的delegate 就是 SessionDelegate = SessionDelegate()橡娄,做的是移交工作笋婿。
//這里是如何實(shí)現(xiàn)將UIApplicationDelegate后臺(tái)的方法橋接到URLSessionDelegate中的初始化方法呻澜。這點(diǎn)體現(xiàn)了SessionDelegate這個(gè)類(lèi)的強(qiáng)大之處嫌术。
self.delegate = delegate
//初始化這個(gè)類(lèi)的URLSession
self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
//提供給SessionDelegate的一些變量初始化
commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
}
commonInit方法的具體實(shí)現(xiàn):
//好吧梢睛,被SessionDelegate 的set方法附身之感
private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
session.serverTrustPolicyManager = serverTrustPolicyManager
//初始化中有self.delegate = delegate,這里有delegate.sessionManager持有self不會(huì)造成循環(huán)引用嗎咖摹?不會(huì)狮含。原因 `weak var sessionManager: SessionManager?`
delegate.sessionManager = self
//這個(gè)主要是給這個(gè)類(lèi)提供backgroundCompletionHandler?()屬性的作用洋满。
delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
}
}
SessionManager與SessionDelegate的關(guān)聯(lián)小節(jié):
open class SessionManager {
public let delegate: SessionDelegate
public init?(delegate: SessionDelegate)
{
self.delegate = delegate
commonInit()
}
private func commonInit() {
delegate.sessionManager = self
}
}
open class SessionDelegate: NSObject {
weak var sessionManager: SessionManager?
}
//這樣雙方互相持有但是是打破循環(huán)鏈的持有剩晴÷嘀洌可以在SessionDelegate中做一些關(guān)于SessionManager的容錯(cuò)處理。
2.Request之DataRequest
下面進(jìn)入今天的正題Request之DataRequest赞弥,首先看request方法:
@discardableResult
open func request(
_ url: URLConvertible,
method: HTTPMethod = .get,//指定是請(qǐng)求的方法類(lèi)型
parameters: Parameters? = nil,//參數(shù)
encoding: ParameterEncoding = URLEncoding.default,//編碼毅整,此處默認(rèn)的是URLEncoding.default
headers: HTTPHeaders? = nil)
-> DataRequest
{
var originalRequest: URLRequest?
do {
originalRequest = try URLRequest(url: url, method: method, headers: headers)
//重點(diǎn)重點(diǎn),編碼重點(diǎn)
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
方法的百分號(hào)編碼和區(qū)分方法的具體實(shí)現(xiàn):
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
//判斷是否有參數(shù)
guard let parameters = parameters else { return urlRequest }
//根據(jù)HTTPMethod這個(gè)枚舉進(jìn)行派分
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 {
//進(jìn)行百分號(hào)編碼和添加&符號(hào)绽左。
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
}
private func query(_ parameters: [String: Any]) -> String {
//創(chuàng)建元祖
var components: [(String, String)] = []
//遍歷
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
//進(jìn)行遞歸操作去除key悼嫉,value
components += queryComponents(fromKey: key, value: value)
}
//joined添加&分隔符,實(shí)例:A&B&C
return components.map { "\($0)=\($1)" }.joined(separator: "&")
}
從request方法閉包中的return request(encodedURLRequest)
方法可以看出走的是下面這步
@discardableResult
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
var originalRequest: URLRequest?
do {
//保存的請(qǐng)求
originalRequest = try urlRequest.asURLRequest()
//保存的任務(wù)
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
//重點(diǎn)點(diǎn)擊進(jìn)入下面代碼拼窥,RequestTask是枚舉戏蔑,區(qū)分了.data,.download,.stream,.upload
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
//task和Request是意義對(duì)應(yīng)的關(guān)聯(lián)關(guān)系。
delegate[task] = request
if startRequestsImmediately { request.resume() }
return request
} catch {
return request(originalRequest, failedWith: error)
}
}
//保存了DataRequest的task適配器請(qǐng)求序列
struct Requestable: TaskConvertible {
let urlRequest: URLRequest
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
do {
let urlRequest = try self.urlRequest.adapt(using: adapter)
//重點(diǎn)是通過(guò)請(qǐng)求找到dataTask
return queue.sync { session.dataTask(with: urlRequest) }
} catch {
throw AdaptError(error: error)
}
}
}
這個(gè)Request的初始化主要是一些與task的代理之間的持有關(guān)系和保存一些值鲁纠。
open class Request{
init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
//session這是是用來(lái)進(jìn)行保存session的总棵。
self.session = session
// requestTask是一個(gè)枚舉,進(jìn)行任務(wù)和代理的分發(fā)
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
//此處這個(gè)線程添加了addOperation 改含,其初始化見(jiàn)下面代碼情龄。
delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
}
}
open class TaskDelegate: NSObject {
init(task: URLSessionTask?) {
//關(guān)于task代理中線程的初始化
self.queue = {
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 1
operationQueue.isSuspended = true
operationQueue.qualityOfService = .utility
return operationQueue
}()
}
}
總結(jié):
1)delegate[task] = request
這樣設(shè)計(jì)的原因是什么?
原因是實(shí)現(xiàn)SessionManager和Request之間的解耦捍壤。
2)那么SessionManager骤视,Request,Task之間各自負(fù)責(zé)什么職能又是如何聯(lián)系的鹃觉?
SessionManager通過(guò)SessionDelegate來(lái)做請(qǐng)求的主體序列专酗,通過(guò)這個(gè)來(lái)塞入一些頭信息。請(qǐng)求體就有DataRequest等Request來(lái)負(fù)責(zé)帜慢,他負(fù)責(zé)的是一些URL笼裳,params,Method粱玲,Ecode躬柬,header等的打包,請(qǐng)求得開(kāi)線程啊抽减,線程這部分就分離出來(lái)由task負(fù)責(zé)允青,并且是Request和task是一對(duì)一的對(duì)練關(guān)系。