Alamofire源碼閱讀(二)--一個GET請求的流程

本文通過一個get請求,追蹤代碼流程,來進入到整個框架的學(xué)習(xí)。

1.創(chuàng)建請求

Alamofire.request("https://httpbin.org/get")
  • 通過Alamofire來創(chuàng)建
@discardableResult
public func request(
    _ url: URLConvertible,
    method: HTTPMethod = .get,
    parameters: Parameters? = nil,
    encoding: ParameterEncoding = URLEncoding.default,
    headers: HTTPHeaders? = nil)
    -> DataRequest
{
    return SessionManager.default.request(
        url,
        method: method,
        parameters: parameters,
        encoding: encoding,
        headers: headers
    )
}
  • 關(guān)鍵字@discardableResult,在方法沒有返回值時不會報出警告
  • swift參數(shù)是支持默認值的,調(diào)用時值傳了一個url參數(shù),繼承URLConvertible協(xié)議,用來生成URL類型
  • HTTPMethod是一個枚舉類型,這里默認值使用get
  • Parameters定義為[String: Any],默認是nil。它的定義使用typealias關(guān)鍵字,用來為已經(jīng)存在的類型重新定義名字的,通過命名,可以使代碼變得更加清晰。HTTPHeaders亦是如此
  • Alamofire只是一個入口,內(nèi)部調(diào)用SessionManager來完成創(chuà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)
            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
            return request(encodedURLRequest)
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }
  • 聲明originalRequest變量,類型是URLRequest。Swift里不會自動給變量賦初始值,也就是說變量不會有默認值,所以要求使用變量之前必須要對其初始化,如果沒有初始化就會報錯。這時候可以使用optional類型,也就是后面跟一個"?"。
  • 試著創(chuàng)建URLRequest,這里加try是因為asURL可能會拋出異常
  • 然后調(diào)用ParameterEncoding.swift的方法對參數(shù)進行編碼
  • 最后進入request方法來生成DataRequest
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)
        }
    }
  • originalTask值是一個結(jié)構(gòu)體,這個結(jié)構(gòu)體繼承TaskConvertible協(xié)議。該協(xié)議定義了task方法,讓每種不同類型的request實現(xiàn)自己創(chuàng)建task的邏輯。這里創(chuàng)建NSURLSessionDataTask類型task的實現(xiàn)代碼是session.dataTask(with: urlRequest)
  • 用session和.data(originalTask, task)創(chuàng)建DataRequest。URLRequest(DataRequest的父類)初始化方法會根據(jù)task的不同生成對應(yīng)的taskDelegate
  • 把task和request的關(guān)系存到delegate中,調(diào)用request的resume方法發(fā)出請求,內(nèi)部會觸發(fā)task.resume()方法發(fā)請求,最后并返回request

整個過程大致是,調(diào)用SessionManager.request()方法,獲取URLRerequest,獲取對應(yīng)的task,創(chuàng)建DataRequest,發(fā)起請求。

2.接收請求

if let request = request as? DataRequest {
            request.responseString { response in
                requestComplete(response.response, response.result)
            }
        }
  • 這里剛開始可能看不太懂,這是尾隨閉包的寫法。這個閉包是request.responseString方法的最后一個參數(shù)。
  • 這個閉包會被加入到DataRequest的delegate.queue中。TaskDelegate的queue是一個串行隊列,存放task結(jié)束之后需要執(zhí)行的任務(wù)
@discardableResult
    public func response<T: DataResponseSerializerProtocol>(
        queue: DispatchQueue? = nil,
        responseSerializer: T,
        completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
        -> Self
    {
        delegate.queue.addOperation {
            let result = responseSerializer.serializeResponse(
                self.request,
                self.response,
                self.delegate.data,
                self.delegate.error
            )

            var dataResponse = DataResponse<T.SerializedObject>(
                request: self.request,
                response: self.response,
                data: self.delegate.data,
                result: result,
                timeline: self.timeline
            )

            dataResponse.add(self.delegate.metrics)

            (queue ?? DispatchQueue.main).async {
                completionHandler(dataResponse)
            }
        }

        return self
    }
  • 最終傳進來的閉包會加入到delegate的queue隊列中,并且這個隊列初始化時設(shè)置了isSuspend=true,所以它會在改為false才會執(zhí)行
  • 這個opration里會生成result和response,供回調(diào)使用,也就是requestComplete(response.response, response.result)的參數(shù)
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繼承URLSessionDataDelegate,實現(xiàn)請求的各種回調(diào)
  • 下面的判斷會走到else,前面在delegate存儲過task和delegate,所以這里self[dataTask]會得到之前發(fā)請求的request,并且是DataTaskDelegate類型
  • 于是執(zhí)行delegate(DataTaskDelegate)的對應(yīng)方法
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) }
            }
        }
    }
  • dataStream為((_ data: Data) -> Void)?類型,mutableData被初始化為Data(),它們都是是DataTaskDelegate的實例變量。這里會走到mutableData.append(data)
  • bytesReceived計算接收數(shù)據(jù)的大小
  • totalBytesExpected將可選類型dataTask.response解包,然后獲取expectedContentLength.“??"運算符可以用于判斷變量或常量的數(shù)值是否是nil,不為nil則取變量或者常量本身的值,如果是nil則使用后面的值替代
  • 判斷是否有progressHandler,這不會調(diào)用。因為demo中并沒有傳
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
            guard let strongSelf = self else { return }

            strongSelf.taskDidComplete?(session, task, error)

            strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error)

            NotificationCenter.default.post(
                name: Notification.Name.Task.DidComplete,
                object: strongSelf,
                userInfo: [Notification.Key.Task: task]
            )

            strongSelf[task] = nil
        }

        guard let request = self[task], let sessionManager = sessionManager else {
            completeTask(session, task, error)
            return
        }

        request.validations.forEach { $0() }

        var error: Error? = error

        if request.delegate.error != nil {
            error = request.delegate.error
        }

        if let retrier = retrier, let error = error {
            retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
                guard shouldRetry else { completeTask(session, task, error) ; return }

                DispatchQueue.utility.after(timeDelay) { [weak self] in
                    guard let strongSelf = self else { return }

                    let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false

                    if retrySucceeded, let task = request.task {
                        strongSelf[task] = request
                        return
                    } else {
                        completeTask(session, task, error)
                    }
                }
            }
        } else {
            completeTask(session, task, error)
        }
    }
  • SessionDelegate內(nèi)實現(xiàn)的回調(diào),表示task已經(jīng)完成數(shù)據(jù)傳輸
  • completeTask,如果請求不需要重試,就會執(zhí)行這個閉包
  • sessionManager沒有被賦值,所以不會走到第一個判斷里
  • validations是[() -> Void] = []一種閉包類型的數(shù)組,放一些檢查的方法。$0()表示第一個參數(shù),也就是數(shù)組里的每一個值
  • 用request.delegate.error取到錯誤,如果設(shè)置了retrier并有error,就執(zhí)行重試的方法。否則執(zhí)行completeTask
  • 在completeTask中,首選判斷taskDidComplete有無值然后執(zhí)行,然后通過strongSelf[task]得到request并調(diào)用其urlSession方法
  • 最后發(fā)通知并把task置為nil
@objc(URLSession:task:didCompleteWithError:)
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let taskDidCompleteWithError = taskDidCompleteWithError {
            taskDidCompleteWithError(session, task, error)
        } else {
            if let error = error {
                if self.error == nil { self.error = error }

                if
                    let downloadDelegate = self as? DownloadTaskDelegate,
                    let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
                {
                    downloadDelegate.resumeData = resumeData
                }
            }

            queue.isSuspended = false
        }
    }
  • 上述代碼 strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error) 的方法實現(xiàn)
  • 這里在有錯誤時,對DownloadTaskDelegate做了一些處理。
  • queue.isSuspended這里是關(guān)鍵,isSuspended設(shè)置為false后,回調(diào)傳進來operation將會開始執(zhí)行
  • @objc 作用:1,fileprivate 或者 private 保證方法私有 能在同一個類 或者 同一個文件(extension)中訪問這個方法 如果定義為private 那么只能在一個類中訪問 不能在類擴展中訪問;2,允許這個函數(shù)在“運行時”通過oc的消息機制調(diào)用
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
        }
    }
  • 上述代碼strongSelf[task] = nil的實現(xiàn)
  • 使用lock,保證賦值是線程安全的
  • open關(guān)鍵字,訪問控制在權(quán)限。在swift3中,fileprivate來顯式的表明,這個元素的訪問權(quán)限為文件內(nèi)私有,即extension也可以訪問到。private則是真正的私有,離開了這個類或者結(jié)構(gòu)體的作用域外面就無法訪問。open在module內(nèi)可以被override,在被import到其他地方后其他用戶使用的時候不能被override。通過open和public標記區(qū)別一個元素在其他module中是只能被訪問還是可以被override
  • defer關(guān)鍵字,推遲執(zhí)行,會在return之前執(zhí)行。記得react cocoa里面oc有寫過一個黑魔法來實現(xiàn)這個方法,swift可以直接用關(guān)鍵字解決了

整理一下整個過程,把完成的閉包傳入,然后被加到queue中,請求返回后出發(fā)queue執(zhí)行,最終調(diào)用最初傳入的閉包

這篇文章從demo里的Alamofire.request("https://httpbin.org/get")開始分析了整個發(fā)送和接收請求的過程,有一個大概流程的概念。后面再去逐個分析每個類

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

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,540評論 19 139
  • 1. Alamofire結(jié)構(gòu) Alamofire全部實現(xiàn)共有17個文件組成,如下: Alamofire有五模塊組成...
    繁華落盡丶lee閱讀 2,066評論 0 3
  • 本篇是Alamofire中的請求抽象層的講解 前言 在Alamofire中,圍繞著Request,設(shè)計了很多額外的...
    老馬的春天閱讀 2,363評論 0 11
  • 如果,有一天,我們的距離越來越遠 不是你變了,而是,我真的愛上你了…… 如果,有一天,我們只是相擁而沒有言語 不是...
    靜曉懶閱讀 317評論 0 1
  • 如果我們在人生中體驗的每一次轉(zhuǎn)變都讓我們在生活中走得更遠,那么,我們就真正體驗到了生活想讓我們體驗的東西。 ——《...
    張書畫閱讀 468評論 1 2

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