【Alamofire源碼解析】07 - SessionManager

SessionManager的作用是用于創(chuàng)建各種請(qǐng)求。

1. MultipartFormDataEncodingResult輔助類型

MultipartFormDataEncodingResult用于表示編碼多表單的結(jié)果,是一個(gè)枚舉,并關(guān)聯(lián)了一些相關(guān)信息。

public enum MultipartFormDataEncodingResult {
    case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)
    case failure(Error)
}

2. 屬性

// 默認(rèn)的SessionManager
open static let `default`: SessionManager = {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
    
    return SessionManager(configuration: configuration)
}()

// 默認(rèn)請(qǐng)求頭
open static let defaultHTTPHeaders: HTTPHeaders = {
}()

// 多表單編碼時(shí)使用的內(nèi)存臨界值, `10_000_000`下劃線使得讀者更容易讀
open static let multipartFormDataEncodingMemoryThreshold: UInt64 = 10_000_000

// 底層的URLSession
open let session: URLSession

// 底層URLSession的代理,session的所有代理都由它來(lái)處理
open let delegate: SessionDelegate

// 是否馬上開(kāi)啟請(qǐng)求,默認(rèn)是true
open var startRequestsImmediately: Bool = true

// 請(qǐng)求適配器
open var adapter: RequestAdapter?

// 請(qǐng)求重試器,由代理提供(如果想要請(qǐng)求失敗的時(shí)候重試,我們需要定義一個(gè)請(qǐng)求重試器)
open var retrier: RequestRetrier? {
    get { return delegate.retrier }
    set { delegate.retrier = newValue }
}

// 默認(rèn)是nil。如果設(shè)置了這個(gè)handler,SessionDelegate的 `sessionDidFinishEventsForBackgroundURLSession`會(huì)自動(dòng)執(zhí)行這個(gè)handler;
// 如果想要在這個(gè)handler執(zhí)行前去處理自己的event,
// 我們要重寫 `sessionDidFinishEventsForBackgroundURLSession`,然后手動(dòng)調(diào)用這個(gè)handler
open var backgroundCompletionHandler: (() -> Void)?

// 執(zhí)行隊(duì)列
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必須是同一個(gè))
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)
}

// 上面兩個(gè)初始化器相同的一些初始化
private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
    session.serverTrustPolicyManager = serverTrustPolicyManager

    delegate.sessionManager = self

    // 把`backgroundCompletionHandler`傳給`delegate.sessionDidFinishEventsForBackgroundURLSession`
    // `[weak self] session`這里的`session`在closure里面沒(méi)有用到,為了代碼簡(jiǎn)潔,其實(shí)應(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ù)請(qǐng)求

// 提供`URLConvertible`,創(chuàng)建數(shù)據(jù)請(qǐng)求
@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ù)編碼到請(qǐng)求上
        let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
        return request(encodedURLRequest)
    } catch {
        return request(originalRequest, failedWith: error)
    }
}

// 提供`URLRequestConvertible`,創(chuàng)建數(shù)據(jù)請(qǐng)求
@discardableResult
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
    var originalRequest: URLRequest?

    do {
        originalRequest = try urlRequest.asURLRequest()
        let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
        
        // 這里其實(shí)是用傳進(jìn)來(lái)的urlRequest,創(chuàng)建了一個(gè)dataTask
        let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
        // 創(chuàng)建DataRequest
        let request = DataRequest(session: session, requestTask: .data(originalTask, task))
        
        // 因?yàn)閐elegate可能要處理多個(gè)請(qǐng)求,作者使用Swift的下標(biāo)特性把請(qǐng)求記錄在delegate的requests字典
        delegate[task] = request

        if startRequestsImmediately { request.resume() }

        return request
    } catch {
        return request(originalRequest, failedWith: error)
    }
}

// 提供`URLRequest`和`error`,創(chuàng)建數(shù)據(jù)請(qǐng)求
// 解決url或者參數(shù)處理過(guò)程可能會(huì)跑出錯(cuò)誤的情況
private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest {
    // 首先聲明一個(gè)關(guān)聯(lián)值為空的data類型的RequestTask
    var requestTask: Request.RequestTask = .data(nil, nil)

    // 如果urlRequest不為空,創(chuàng)建一個(gè)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是適配過(guò)程中出現(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的下標(biāo)特性,可以訪問(wèn)【Swift 3.1】12 - 下標(biāo) (Subscripts)。

5. 下載請(qǐng)求 & 上傳請(qǐng)求 & Stream請(qǐng)求

這三個(gè)請(qǐng)求與數(shù)據(jù)請(qǐng)求的代碼大同小異,大家可以自己深入看看。如果有不懂的,歡迎留言,我看到了會(huì)盡力解答。

6. 重試請(qǐng)求

// 重試請(qǐng)求是否成功
func retry(_ request: Request) -> Bool {
    // 如果請(qǐng)求沒(méi)有任務(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
    }
}

// 實(shí)現(xiàn)重試
private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) {
    // 需要重試的請(qǐng)求可能很多,使用異步隊(duì)列
    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() }
                }
            }
        }
    }
}

有任何問(wèn)題,歡迎大家留言!

歡迎加入我管理的Swift開(kāi)發(fā)群:536353151,本群只討論Swift相關(guān)內(nèi)容。

原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處。謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容