Alamofire 5.0.0-beta.7 源碼閱讀(一)

首先我們先看一下最簡單的一個(gè)請(qǐng)求方法

public static func request(_ url: URLConvertible,
                               method: HTTPMethod = .get,
                               parameters: Parameters? = nil,
                               encoding: ParameterEncoding = URLEncoding.default,
                               headers: HTTPHeaders? = nil,
                               interceptor: RequestInterceptor? = nil) -> DataRequest

解讀一下各個(gè)參數(shù)的意思:

url

我們可以看到url的參數(shù)類型為URLConvertible,點(diǎn)進(jìn)去看一下會(huì)看到這是一個(gè)協(xié)議類型求摇,定義如下

/// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct
/// `URLRequests`.
public protocol URLConvertible {
    /// Returns a `URL` from the conforming instance or throws.
    ///
    /// - Returns: The `URL` created from the instance.
    /// - Throws:  Any error thrown while creating the `URL`.
    func asURL() throws -> URL
}

swift中通過extension可以對(duì)協(xié)議進(jìn)行默認(rèn)實(shí)現(xiàn),Alamofire中對(duì)StringURL兩個(gè)類實(shí)現(xiàn)了該協(xié)議,并添加默認(rèn)實(shí)現(xiàn)如下

extension String: URLConvertible {
    /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws.
    ///
    /// - Returns: The `URL` initialized with `self`.
    /// - Throws:  An `AFError.invalidURL` instance.
    public func asURL() throws -> URL {
        guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }

        return url
    }
}

extension URL: URLConvertible {
    /// Returns `self`.
    public func asURL() throws -> URL { return self }
}

method

請(qǐng)求類型打月,為一個(gè)enum

public enum HTTPMethod: String {
    /// `CONNECT` method.
    case connect = "CONNECT"
    /// `DELETE` method.
    case delete  = "DELETE"
    /// `GET` method.
    case get     = "GET"
    /// `HEAD` method.
    case head    = "HEAD"
    /// `OPTIONS` method.
    case options = "OPTIONS"
    /// `PATCH` method.
    case patch   = "PATCH"
    /// `POST` method.
    case post    = "POST"
    /// `PUT` method.
    case put     = "PUT"
    /// `TRACE` method.
    case trace   = "TRACE"
}

parameters 及 headers

請(qǐng)求參數(shù)及請(qǐng)求頭
Parameters我們可以看到實(shí)際上是一個(gè)別名public typealias Parameters = [String: Any]
HTTPHeaders為一個(gè)結(jié)構(gòu)體辞嗡,持有一個(gè)[HTTPHeader]的數(shù)組不狮,我們可以通過HTTPHeader的構(gòu)造方法來創(chuàng)建header參數(shù)欣除。
HTTPHeaders提供了一些默認(rèn)header

public extension HTTPHeaders {
    /// The default set of `HTTPHeaders` used by Alamofire. Includes `Accept-Encoding`, `Accept-Language`, and
    /// `User-Agent`.
    static let `default`: HTTPHeaders = [.defaultAcceptEncoding,
                                         .defaultAcceptLanguage,
                                         .defaultUserAgent]
}

interceptor

對(duì)于這個(gè)參數(shù),我的理解是在請(qǐng)求前及請(qǐng)求失敗時(shí)候?qū)equest做統(tǒng)一處理的地方潭袱,首先我們看一下這個(gè)協(xié)議的定義

/// Type that provides both `RequestAdapter` and `RequestRetrier` functionality.
public protocol RequestInterceptor: RequestAdapter, RequestRetrier {}

extension RequestInterceptor {
    public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (AFResult<URLRequest>) -> Void) {
        completion(.success(urlRequest))
    }

    public func retry(
        _ request: Request,
        for session: Session,
        dueTo error: Error,
        completion: @escaping (RetryResult) -> Void)
    {
        completion(.doNotRetry)
    }
}

第一個(gè)方法柱嫌,會(huì)在請(qǐng)求發(fā)起之前進(jìn)行調(diào)用,比如我們可以在這個(gè)地方對(duì)urlRequest進(jìn)行一些請(qǐng)求參數(shù)及請(qǐng)求頭的修改屯换;
第二個(gè)方法則會(huì)在請(qǐng)求失敗后進(jìn)行調(diào)用慎式。(有請(qǐng)求結(jié)果,例如response.statusCode = 400之類的不會(huì)調(diào)用趟径,因?yàn)檫@不算一次失敗的請(qǐng)求,當(dāng)然如果我們想讓如此之類的請(qǐng)求也走該回調(diào)方便做統(tǒng)一處理癣防,那么我們的請(qǐng)求方法需要這么寫 Alamofile.request(url).validate().response蜗巧。 中間添加一個(gè)validate)

我們看一下validate具體做了什么:
首先Validation.swift文件中有這么一個(gè)參數(shù)fileprivate var acceptableStatusCodes: Range<Int> { return 200..<300 },也就是200..<300以外的statusCode會(huì)走上邊的retry(_request:for:dueTo:completion)方法

我們看到Validation.swift文件中對(duì)DataRequest有如下擴(kuò)展

extension DataRequest {
    /// Validates that the response has a status code in the specified sequence.
    ///
    /// If validation fails, subsequent calls to response handlers will have an associated error.
    ///
    /// - parameter range: The range of acceptable status codes.
    ///
    /// - returns: The request.
    @discardableResult
    public func validate<S: Sequence>(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {
        return validate { [unowned self] _, response, _ in
            return self.validate(statusCode: acceptableStatusCodes, response: response)
        }
    }
}

該方法蕾盯,調(diào)用了Request.swift文件中的方法

@discardableResult
    public func validate(_ validation: @escaping Validation) -> Self {
        let validator: () -> Void = { [unowned self] in
            guard self.error == nil, let response = self.response else { return }

            let result = validation(self.request, response, self.data)

            if case .failure(let error) = result { self.error = error }

            self.eventMonitor?.request(self,
                                       didValidateRequest: self.request,
                                       response: response,
                                       data: self.data,
                                       withResult: result)
        }

        protectedValidators.append(validator)

        return self
    }

該方法把block保存在protectedValidators中幕屹,當(dāng)請(qǐng)求結(jié)束后,會(huì)對(duì)請(qǐng)求結(jié)果code進(jìn)行一個(gè)比對(duì),如下

func didCompleteTask(_ task: URLSessionTask, with error: Error?) {
        self.error = self.error ?? error
        // 如果我們請(qǐng)求時(shí)調(diào)用了 .validate() 則這個(gè)數(shù)組中便存在對(duì)應(yīng)的 block望拖,進(jìn)行遍歷渺尘,會(huì)把 200..<300 以外的code算為 Error,然后就會(huì)走 retry(_request:for:dueTo:completion) 這個(gè)方法
        protectedValidators.directValue.forEach { $0() }

        eventMonitor?.request(self, didCompleteTask: task, with: error)

        retryOrFinish(error: self.error)
    }

    func retryOrFinish(error: Error?) {
        guard let error = error, let delegate = delegate else { finish(); return }

        delegate.retryResult(for: self, dueTo: error) { retryResult in
            switch retryResult {
            case .doNotRetry, .doNotRetryWithError:
                self.finish(error: retryResult.error)
            case .retry, .retryWithDelay:
                delegate.retryRequest(self, withDelay: retryResult.delay)
            }
        }
    }

上面的protectedValidators.directValue.forEach { $0() }這句代碼會(huì)走到該方法

public func validate(_ validation: @escaping Validation) -> Self {
        let validator: () -> Void = { [unowned self] in
            guard self.error == nil, let response = self.response else { return }

            let result = validation(self.request, response, self.data)

            if case .failure(let error) = result { self.error = error }

            self.eventMonitor?.request(self,
                                       didValidateRequest: self.request,
                                       response: response,
                                       data: self.data,
                                       withResult: result)
        }

        protectedValidators.append(validator)

        return self
    }

這個(gè)方法中的let result = validation(self.request, response, self.data)則會(huì)對(duì)code進(jìn)行對(duì)比

fileprivate func validate<S: Sequence>(
        statusCode acceptableStatusCodes: S,
        response: HTTPURLResponse)
        -> ValidationResult
        where S.Iterator.Element == Int
    {
        if acceptableStatusCodes.contains(response.statusCode) {
            return .success(Void())
        } else {
            let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode)
            return .failure(AFError.responseValidationFailed(reason: reason))
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末说敏,一起剝皮案震驚了整個(gè)濱河市鸥跟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盔沫,老刑警劉巖医咨,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異架诞,居然都是意外死亡拟淮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門谴忧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來很泊,“玉大人,你說我怎么就攤上這事沾谓∥欤” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵搏屑,是天一觀的道長争涌。 經(jīng)常有香客問我,道長辣恋,這世上最難降的妖魔是什么亮垫? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮伟骨,結(jié)果婚禮上饮潦,老公的妹妹穿的比我還像新娘。我一直安慰自己携狭,他們只是感情好继蜡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逛腿,像睡著了一般稀并。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上单默,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天碘举,我揣著相機(jī)與錄音,去河邊找鬼搁廓。 笑死引颈,一個(gè)胖子當(dāng)著我的面吹牛耕皮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝙场,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼凌停,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了售滤?” 一聲冷哼從身側(cè)響起罚拟,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎趴泌,沒想到半個(gè)月后舟舒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗜憔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年秃励,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吉捶。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夺鲜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呐舔,到底是詐尸還是另有隱情币励,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布珊拼,位于F島的核電站食呻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏澎现。R本人自食惡果不足惜仅胞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剑辫。 院中可真熱鬧干旧,春花似錦、人聲如沸妹蔽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胳岂。三九已至编整,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乳丰,已是汗流浹背闹击。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留成艘,地道東北人赏半。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像淆两,于是被迫代替她去往敵國和親断箫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容