Alamifire的Response解析

image

女兒惹她媽媽生氣了,我讓她去道歉催首。
“知錯(cuò)就改扶踊,快去找你媽,認(rèn)錯(cuò)郎任⊙砗模”我催促她。
小家伙猶豫了半天舶治,終于走進(jìn)了廚房分井,對(duì)她媽說(shuō)道:
“媽媽车猬,請(qǐng)問(wèn)你是周二珂嗎?”
妻子很疑惑:“不是啊尺锚≈槿颍”
“哦,對(duì)不起瘫辩,我認(rèn)錯(cuò)了伏嗜。”

哈哈哈伐厌,意淫下承绸。


最近看Alamifire的源碼,不得不說(shuō)挣轨,好的源碼的確讓人獲益良多军熏。

但是看之前會(huì)很懵,如果不熟悉請(qǐng)求流程的話卷扮,很有可能堅(jiān)持不下去荡澎,所以我這里簡(jiǎn)要的把他的一個(gè)請(qǐng)求流程簡(jiǎn)單分析一下,希望能夠幫助到你画饥。

Alamofire.request(posturl, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headerFile).responseJSON { (response) in
        switch response.result{
        case .success(_):
                ///成功
            if let value = response.result.value {
                
            }
        case .failure(_):
                ///失敗
            print(response.result.error)
          }
    }

上面是一個(gè)請(qǐng)求json數(shù)據(jù)的一個(gè)標(biāo)準(zhǔn)用法衔瓮,看源碼可以發(fā)現(xiàn)Alamofire提供了多個(gè)靜態(tài)的請(qǐng)求方法,而這些請(qǐng)求方法全部是通過(guò)SessionManager管理的抖甘。

網(wǎng)圖热鞍,侵刪

由于Alamofire本質(zhì)上是對(duì)URLSession的的一個(gè)封裝,所以我們需要了解下URLSession的結(jié)構(gòu),如上圖一個(gè)session管理者多個(gè)請(qǐng)求的task和回調(diào)的delegate衔彻。所以在SessionManager中我們可以看到一個(gè)靜態(tài)的default常量薇宠,以及類型為SessionDelegate的一個(gè)delegate變量。


接下來(lái)我們分析上面的請(qǐng)求過(guò)程

首先Alamofire將請(qǐng)求分成了幾個(gè)大類

image

這里我就不一個(gè)個(gè)分析了艰额,今天主要分析請(qǐng)求的流程澄港。后面我會(huì)針對(duì)Alamofire中幾個(gè)比較怪的寫法,我們不經(jīng)常用的寫法分析一下柄沮。

Alamofire.request這個(gè)方法調(diào)用的是SessionManager中的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)
    }
}

返回值還是DataRequest回梧,這是為了后面可以鏈?zhǔn)秸{(diào)用.responseJSON


這里的請(qǐng)求步驟簡(jiǎn)單來(lái)說(shuō)是(這里還需要再研究下祖搓,回頭會(huì)專門寫個(gè)文章仔細(xì)分析下)

  • 獲取urlRequest

  • 獲取URLSessionTask

  • sessionURLSessionTask封裝至Request相應(yīng)的子類對(duì)象

這句delegate[task] = request可能一開始看很難看懂狱意,但其實(shí)這是給SessionDelegate定義了下標(biāo)方法,其實(shí)是通過(guò)SessionDelegaterequests屬性來(lái)存儲(chǔ)task對(duì)應(yīng)的request

///通過(guò)自身的requests屬性來(lái)存儲(chǔ)[task: request],用lock來(lái)確保線程安全拯欧。
/// Access the task delegate for the specified task in a thread-safe manner.
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
    }
}

后面的.responseJSON這里是指定對(duì)返回的數(shù)據(jù)進(jìn)行json解析

public func responseJSON(
    queue: DispatchQueue? = nil,
    options: JSONSerialization.ReadingOptions = .allowFragments,
    completionHandler: @escaping (DataResponse<Any>) -> Void)
    -> Self
{
    return response(
        queue: queue,
        responseSerializer: DataRequest.jsonResponseSerializer(options: options),
        completionHandler: completionHandler
    )
}

相信大家看到這里頭肯定大了一圈详囤,講真的,我看到這里頭大的一度想放棄镐作。

[圖片上傳失敗...(image-5840f4-1535621411864)]

但是頭大了之后發(fā)現(xiàn)能思考更多東西了藏姐,這里我來(lái)一個(gè)一個(gè)分解開來(lái)

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
}

首先return調(diào)用了DataRequest的一個(gè)序列化結(jié)果的一個(gè)根方法隆箩,為什么說(shuō)根方法呢,大家可以看下responseString這個(gè)方法中也是return這個(gè)方法,通過(guò)<T: DataResponseSerializerProtocol>這個(gè)泛型參數(shù)就可以實(shí)現(xiàn)請(qǐng)求結(jié)果序列化成任意類型羔杨,只要遵守了DataResponseSerializerProtocol這個(gè)協(xié)議捌臊,并實(shí)現(xiàn)即可。

而這個(gè)協(xié)議中的serializeResponse這個(gè)閉包則是起到傳輸數(shù)據(jù)然后返回序列化的結(jié)果的一個(gè)作用问畅。


下面我闡述下代碼調(diào)用的順序娃属。

  1. 調(diào)用.responseJSON ————> 傳入responseSerializer這個(gè)參數(shù)(系列化的過(guò)程)來(lái)調(diào)用DataRequest的序列化根方法

  2. DataRequest.jsonResponseSerializer(options: options)這里就是序列化的方法,我盡量在注釋中描述清楚

     public static func jsonResponseSerializer(
         options: JSONSerialization.ReadingOptions = .allowFragments)
         -> DataResponseSerializer<Any>
     {
          ///返回的是遵守DataResponseSerializerProtocol協(xié)議的一個(gè)結(jié)構(gòu)體對(duì)象
          ///這是一個(gè)初始化方法护姆,初始化的對(duì)象存儲(chǔ)了一個(gè)閉包矾端。
         return DataResponseSerializer { _, response, data, error in
             return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
         }
         
         ///所以上面可以等價(jià)為
         let jsonResponseSerializer = DataResponseSerializer.init { (request, response, data, error) -> Result<Any> in
         
                     ///這里就是根據(jù)閉包傳過(guò)來(lái)的response, data, error來(lái)對(duì)結(jié)果進(jìn)行序列化。
         return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
             
         }
         return jsonResponseSerializer
         
     }
    
  3. 接下來(lái)看DataRequest的序列化根方法的實(shí)現(xiàn)卵皂,我們可以看到

     let result = responseSerializer.serializeResponse(
             self.request,
             self.response,
             self.delegate.data,
             self.delegate.error
         )
    

這里的responseSerializer.serializeResponse傳遞參數(shù)然后調(diào)用第二步中序列化操作秩铆,最后得到return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)返回值

  1. 最后將得到的序列化結(jié)果result以及其他數(shù)據(jù)封裝在dataResponse中通過(guò)completionHandler在指定線程中回調(diào)。

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

這里對(duì)協(xié)議的關(guān)聯(lián)類型以及屬性的應(yīng)用值得我們認(rèn)真拜讀一下

最終

最近很迷茫灯变,來(lái)個(gè)人私信我陪我聊聊騷啊殴玛。

聯(lián)系方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市添祸,隨后出現(xiàn)的幾起案子滚粟,更是在濱河造成了極大的恐慌,老刑警劉巖刃泌,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凡壤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡耙替,警方通過(guò)查閱死者的電腦和手機(jī)亚侠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)俗扇,“玉大人硝烂,你說(shuō)我怎么就攤上這事⊥模” “怎么了滞谢?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)除抛。 經(jīng)常有香客問(wèn)我爹凹,道長(zhǎng),這世上最難降的妖魔是什么镶殷? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮微酬,結(jié)果婚禮上绘趋,老公的妹妹穿的比我還像新娘颤陶。我一直安慰自己,他們只是感情好陷遮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布滓走。 她就那樣靜靜地躺著,像睡著了一般帽馋。 火紅的嫁衣襯著肌膚如雪搅方。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天绽族,我揣著相機(jī)與錄音姨涡,去河邊找鬼。 笑死吧慢,一個(gè)胖子當(dāng)著我的面吹牛涛漂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播检诗,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匈仗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了逢慌?” 一聲冷哼從身側(cè)響起悠轩,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎攻泼,沒(méi)想到半個(gè)月后火架,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坠韩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年距潘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只搁。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡音比,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出氢惋,到底是詐尸還是另有隱情洞翩,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布焰望,位于F島的核電站骚亿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏熊赖。R本人自食惡果不足惜来屠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俱笛,春花似錦捆姜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至磕仅,卻和暖如春珊豹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榕订。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工店茶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卸亮。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓忽妒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親兼贸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子段直,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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