SessionManager
的作用是用于創(chuàng)建各種請求女仰。
1. MultipartFormDataEncodingResult
輔助類型
MultipartFormDataEncodingResult
用于表示編碼多表單的結(jié)果,是一個枚舉,并關(guān)聯(lián)了一些相關(guān)信息硬耍。
public enum MultipartFormDataEncodingResult {
case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)
case failure(Error)
}
2. 屬性
// 默認的SessionManager
open static let `default`: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return SessionManager(configuration: configuration)
}()
// 默認請求頭
open static let defaultHTTPHeaders: HTTPHeaders = {
}()
// 多表單編碼時使用的內(nèi)存臨界值, `10_000_000`下劃線使得讀者更容易讀
open static let multipartFormDataEncodingMemoryThreshold: UInt64 = 10_000_000
// 底層的URLSession
open let session: URLSession
// 底層URLSession的代理,session的所有代理都由它來處理
open let delegate: SessionDelegate
// 是否馬上開啟請求米罚,默認是true
open var startRequestsImmediately: Bool = true
// 請求適配器
open var adapter: RequestAdapter?
// 請求重試器浮定,由代理提供(如果想要請求失敗的時候重試相满,我們需要定義一個請求重試器)
open var retrier: RequestRetrier? {
get { return delegate.retrier }
set { delegate.retrier = newValue }
}
// 默認是nil层亿。如果設(shè)置了這個handler,SessionDelegate的 `sessionDidFinishEventsForBackgroundURLSession`會自動執(zhí)行這個handler立美;
// 如果想要在這個handler執(zhí)行前去處理自己的event匿又,
// 我們要重寫 `sessionDidFinishEventsForBackgroundURLSession`,然后手動調(diào)用這個handler
open var backgroundCompletionHandler: (() -> Void)?
// 執(zhí)行隊列
let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString)
3. 初始化
// 傳入`configuration`和`delegate`悯辙,創(chuàng)建SessionManager
public init(
configuration: URLSessionConfiguration = URLSessionConfiguration.default,
delegate: SessionDelegate = SessionDelegate(),
serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
self.delegate = delegate
self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
// 傳入`session`和`delegate`琳省,創(chuàng)建SessionManager(注意:session的delegate和傳入的delegate必須是同一個)
public init?(
session: URLSession,
delegate: SessionDelegate,
serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
{
guard delegate === session.delegate else { return nil }
self.delegate = delegate
self.session = session
commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
}
// 上面兩個初始化器相同的一些初始化
private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
session.serverTrustPolicyManager = serverTrustPolicyManager
delegate.sessionManager = self
// 把`backgroundCompletionHandler`傳給`delegate.sessionDidFinishEventsForBackgroundURLSession`
// `[weak self] session`這里的`session`在closure里面沒有用到迎吵,為了代碼簡潔躲撰,其實應(yīng)該用`_`代替的
delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
guard let strongSelf = self else { return }
DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
}
}
// 被回收了之后,使session失效
deinit {
session.invalidateAndCancel()
}
4. 數(shù)據(jù)請求
// 提供`URLConvertible`击费,創(chuàng)建數(shù)據(jù)請求
@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)
// 使用指定的`encoding`拢蛋,把參數(shù)編碼到請求上
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
return request(encodedURLRequest)
} catch {
return request(originalRequest, failedWith: error)
}
}
// 提供`URLRequestConvertible`,創(chuàng)建數(shù)據(jù)請求
@discardableResult
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
var originalRequest: URLRequest?
do {
originalRequest = try urlRequest.asURLRequest()
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
// 這里其實是用傳進來的urlRequest蔫巩,創(chuàng)建了一個dataTask
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
// 創(chuàng)建DataRequest
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
// 因為delegate可能要處理多個請求谆棱,作者使用Swift的下標特性把請求記錄在delegate的requests字典
delegate[task] = request
if startRequestsImmediately { request.resume() }
return request
} catch {
return request(originalRequest, failedWith: error)
}
}
// 提供`URLRequest`和`error`,創(chuàng)建數(shù)據(jù)請求
// 解決url或者參數(shù)處理過程可能會跑出錯誤的情況
private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest {
// 首先聲明一個關(guān)聯(lián)值為空的data類型的RequestTask
var requestTask: Request.RequestTask = .data(nil, nil)
// 如果urlRequest不為空圆仔,創(chuàng)建一個data類型的RequestTask
if let urlRequest = urlRequest {
let originalTask = DataRequest.Requestable(urlRequest: urlRequest)
requestTask = .data(originalTask, nil)
}
let underlyingError = error.underlyingAdaptError ?? error
let request = DataRequest(session: session, requestTask: requestTask, error: underlyingError)
// 如果自定了以重試器垃瞧,并且error是適配過程中出現(xiàn)的error,那么允許重試
if let retrier = retrier, error is AdaptError {
allowRetrier(retrier, toRetry: request, with: underlyingError)
} else {
if startRequestsImmediately { request.resume() }
}
return request
}
關(guān)于Swift的下標特性坪郭,可以訪問【Swift 3.1】12 - 下標 (Subscripts)个从。
5. 下載請求 & 上傳請求 & Stream請求
這三個請求與數(shù)據(jù)請求的代碼大同小異,大家可以自己深入看看歪沃。如果有不懂的嗦锐,歡迎留言,我看到了會盡力解答沪曙。
6. 重試請求
// 重試請求是否成功
func retry(_ request: Request) -> Bool {
// 如果請求沒有任務(wù)奕污,則重試失敗
guard let originalTask = request.originalTask else { return false }
do {
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
request.delegate.task = task // resets all task delegate data
request.retryCount += 1
request.startTime = CFAbsoluteTimeGetCurrent()
request.endTime = nil
task.resume()
return true
} catch {
request.delegate.error = error.underlyingAdaptError ?? error
return false
}
}
// 實現(xiàn)重試
private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) {
// 需要重試的請求可能很多,使用異步隊列
DispatchQueue.utility.async { [weak self] in
guard let strongSelf = self else { return }
retrier.should(strongSelf, retry: request, with: error) { shouldRetry, timeDelay in
guard let strongSelf = self else { return }
guard shouldRetry else {
if strongSelf.startRequestsImmediately { request.resume() }
return
}
DispatchQueue.utility.after(timeDelay) {
guard let strongSelf = self else { return }
// 是否重試成功
let retrySucceeded = strongSelf.retry(request)
// 如果重試成功液走,更新delegate的requests字典
if retrySucceeded, let task = request.task {
strongSelf.delegate[task] = request
} else {
if strongSelf.startRequestsImmediately { request.resume() }
}
}
}
}
}
有任何問題碳默,歡迎大家留言!
歡迎加入我管理的Swift開發(fā)群:536353151
缘眶,本群只討論Swift相關(guān)內(nèi)容腻窒。
原創(chuàng)文章,轉(zhuǎn)載請注明出處磅崭。謝謝儿子!