Alamofire学习 - Response

733 阅读5分钟

前言

在前面几篇内容中已经大致介绍了AlamofireRequest请求,当一个Request完成的时候,下一步 肯定要处理服务器返回的响应数据。本篇内容就记录一下学习处理响应数据Response的内容。

Response

先来一个简单的代码例子🌰看一下下:

SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .response { (response) in
                debugPrint(response)
        }

我们都知道Alamofire可以使用链式访问,那就搞点事做😏,把requestresponse换一下,先进行response,再进行request,换了之后会发现根本不可能😞。这就说明了request必须要在response之前访问,这也提现了request的重要性

好了,在皮一下之后,回到代码来看,看一下这个response是怎么实现的:

这里可以看到response的任务是加入到了 delegate.queue.addOperation,这个delegate.queue就是在发起request之后,创建的TaskDelegate会默认初始化一个挂起队列。(具体请看上篇时间轴部分)然后在request请求Complete之后再取消队列的挂起,保证了队列中的任务全部是在request请求完成之后进行的,这同样也更加说明了request必须要在response之前访问。

然后任务被交给了主队列(毕竟开发者有可能利用response进行UI的更新),可以看到在这里并没有对response进行序列化,而是初始化了一个DefaultDataResponse类的对象,

DefaultDataResponse是用来保存self.requestself.responseself.delegate.dataself.delegate.errorself.timelineself.delegate.metrics 属性,并把初始化的DefaultDataResponse对象返回给completionHandler 闭包。(有点类似于Model,一般来说,在swift中,如果只是为了保存数据,那么应该把这个类设计成structstruct是值传递,因此对数据的操作更安全。除了定义需要保存的数据属性后,必须设计一个符合要求的构造函数。),

小总结:

  • request(该响应来源于那个请求)
  • response(服务器返回的响应)
  • data(响应数据)
  • error(在请求中可能发生的错误)
  • timeline(请求的时间轴封装)
  • _metrics(包含了请求和响应的统计信息)

这些数据都不是由response来创建的,它只有使用权。也就是说response只是一个数据的保存信息者,把各种数据化零为整返回给用户。

Response序列化

Alamofire中把Request分为了4类:

  • DataRequest
  • DownloadRequest
  • UploadRequest
  • StreamRequest

因为有四种不同的Request类型,StreamRequest我们先a按下不表,对于UploadRequest来说,服务器响应的数据比较简单,就响应一个结果就行,因此不需要对它的Response专门进行封装。因此,Alamofire设计了2种与之相对应的Response类型

  • DefaultDataResponse / DataResponse
  • DefaultDownloadResponse / DataResponse

细心的你一定会发现在DataRequest 的扩展的中会有两个response方法,(第一个response方法在上面👆已经给出,下面👇贴出第二个response

在这个序列化的response方法内部,可以看到会先进行一个serializeResponse的操作得到一个结果result,然后在初始化一个DataResponse对象用来保存 self.requestself.responseself.delegate.dataresultself.timelineself.delegate.metrics这些数据,并把DataResponse对象返回给completionHandler 闭包。

如果你对比这两个response方法,聪明而优秀的你就会发现这两个方法的不同之处:

request请求完成之后,获取到的是没有经过序列化后的数据,如果调用了没有序列化的response方法,DefaultDataResponse/DefaultDownloadResponse。如果调用了序列化的response方法,需要传入一个泛型的responseSerializer 参数,返回的就是DataResponse

可以看到这个序列化的response方法遵循了DataResponseSerializerProtocol协议,下面通过源码看一下这个协议的具体实现:
在这个协议内部有一个序列化函数serializeResponse,并返回一个类型为SerializedObject的Result,那么也就是说序列者只需要遵循这个协议就可以了:所以就有了这样一个用序列化函数serializeResponse作为参数来初始化,并且保存序列化函数的DataResponseSerializer类;

从这里我们知道调用序列化函数serializeResponse会返回一个Result,而且在前面也已经说过,在序列化的response方法内部,看到会先进行一个serializeResponse的操作得到一个结果result

可以看到关于Result的结果只有两种:成功和失败。成功就把序列化完成的数据返回,失败就返回一个error信息。

Response扩展

如果我想把请求的结果序列化成json类型或者String类型的,怎么办,难道调用序列化的response方法拿到返回的内容之后,用户此时再去自己做序列化成json类型或者String类型的内容?怎么可能,霸气侧漏的Alamofire早就已经都做好了。

SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .response { (response) in
               
        }
SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .responseData { (responsedata) in
              
        }
SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .responseString { (responseString) in
                
        }
SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .responseJSON { (responsejson) in
                
        }
SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
            .responsePropertyList{ (responselist) in
                
        }

responseData

responseData在其方法内部是直接调用了response的序列化方法,那么也就是和response一样,把数据序列化为Data类型也就是Result

这里传入的序列化器responseSerializer的参数是DataRequest.dataResponseSerializer(),下面来看一下dataResponseSerializer()

返回的就是DataResponseSerializer 类型的序列化器,DataResponseSerializer这个类前面已经介绍过,它是用来保存序列化函数的,关键在于Request.serializeResponseData

这里会根据序列化的成功和失败来返回数据,返回.success(validData)或者 .failure(error信息)

注解:emptyDataStatusCodes

如果HTTP response code204或者205,就表示Datanil.

关于responseStringresponseJSONresponsePropertyList在内部是如何实现的,在这里就不一一列出来了,基本和responseData的套路一样,有兴趣的大佬可以借助源码去看一下。

总结

实际上这个response并不是我们常见的那种response,它只是一个保存内容的载体,它把requestresponsedataerrortimeline_metrics 这些数据全部收集整合起来,放到自己身上,然后一起返回给用户,这样用户在外面可以拿到他想要的任何数据,这是多么牛X的处理方式。