Alamifire的Response解析

image

女儿惹她妈妈生气了,我让她去道歉。
“知错就改,快去找你妈,认错。”我催促她。
小家伙犹豫了半天,终于走进了厨房,对她妈说道:
“妈妈,请问你是周二珂吗?”
妻子很疑惑:“不是啊。”
“哦,对不起,我认错了。”

哈哈哈,意淫下。


最近看Alamifire的源码,不得不说,好的源码的确让人获益良多。

但是看之前会很懵,如果不熟悉请求流程的话,很有可能坚持不下去,所以我这里简要的把他的一个请求流程简单分析一下,希望能够帮助到你。

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)
          }
    }

上面是一个请求json数据的一个标准用法,看源码可以发现Alamofire提供了多个静态的请求方法,而这些请求方法全部是通过SessionManager管理的。

网图,侵删

由于Alamofire本质上是对URLSession的的一个封装,所以我们需要了解下URLSession的结构,如上图一个session管理者多个请求的task和回调的delegate。所以在SessionManager中我们可以看到一个静态的default常量,以及类型为SessionDelegate的一个delegate变量。


接下来我们分析上面的请求过程

首先Alamofire将请求分成了几个大类

image

这里我就不一个个分析了,今天主要分析请求的流程。后面我会针对Alamofire中几个比较怪的写法,我们不经常用的写法分析一下。

Alamofire.request这个方法调用的是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,这是为了后面可以链式调用.responseJSON


这里的请求步骤简单来说是(这里还需要再研究下,回头会专门写个文章仔细分析下)

  • 获取urlRequest

  • 获取URLSessionTask

  • sessionURLSessionTask封装至Request相应的子类对象

这句delegate[task] = request可能一开始看很难看懂,但其实这是给SessionDelegate定义了下标方法,其实是通过SessionDelegaterequests属性来存储task对应的request

///通过自身的requests属性来存储[task: request],用lock来确保线程安全。
/// 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这里是指定对返回的数据进行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)]

但是头大了之后发现能思考更多东西了,这里我来一个一个分解开来

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调用了DataRequest的一个序列化结果的一个根方法,为什么说根方法呢,大家可以看下responseString这个方法中也是return这个方法,通过<T: DataResponseSerializerProtocol>这个泛型参数就可以实现请求结果序列化成任意类型,只要遵守了DataResponseSerializerProtocol这个协议,并实现即可。

而这个协议中的serializeResponse这个闭包则是起到传输数据然后返回序列化的结果的一个作用。


下面我阐述下代码调用的顺序。

  1. 调用.responseJSON ————> 传入responseSerializer这个参数(系列化的过程)来调用DataRequest的序列化根方法

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

     public static func jsonResponseSerializer(
         options: JSONSerialization.ReadingOptions = .allowFragments)
         -> DataResponseSerializer<Any>
     {
          ///返回的是遵守DataResponseSerializerProtocol协议的一个结构体对象
          ///这是一个初始化方法,初始化的对象存储了一个闭包。
         return DataResponseSerializer { _, response, data, error in
             return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
         }
         
         ///所以上面可以等价为
         let jsonResponseSerializer = DataResponseSerializer.init { (request, response, data, error) -> Result<Any> in
         
                     ///这里就是根据闭包传过来的response, data, error来对结果进行序列化。
         return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
             
         }
         return jsonResponseSerializer
         
     }
    
  3. 接下来看DataRequest的序列化根方法的实现,我们可以看到

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

这里的responseSerializer.serializeResponse传递参数然后调用第二步中序列化操作,最后得到return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)返回值

  1. 最后将得到的序列化结果result以及其他数据封装在dataResponse中通过completionHandler在指定线程中回调。

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

这里对协议的关联类型以及属性的应用值得我们认真拜读一下

最终

最近很迷茫,来个人私信我陪我聊聊骚啊。

联系方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容