在前面几篇内容中已经大体介绍了Alamofire
的Request
请求,当一个Request
完成的时候,下一步 确定要处理服务器返回的响应数据。本篇内容就记录一下学习处理响应数据Response
的内容。json
先来一个简单的代码例子🌰看一下下:swift
SessionManager.default.request("https://www.douban.com/j/app/radio/channels")
.response { (response) in
debugPrint(response)
}
复制代码
咱们都知道Alamofire
可使用链式访问,那就搞点事作😏,把request
和response
换一下,先进行response
,再进行request
,换了以后会发现根本不可能😞。这就说明了request
必需要在response
以前访问,这也提现了request
的重要性安全
好了,在皮一下以后,回到代码来看,看一下这个response
是怎么实现的:bash
response
的任务是加入到了
delegate.queue.addOperation
,这个
delegate.queue
就是在发起
request
以后,建立的
TaskDelegate
会默认初始化一个挂起队列。(具体请看上篇
时间轴部分)而后在
request
请求
Complete
以后再取消队列的挂起,保证了队列中的任务所有是在
request
请求完成以后进行的,
这一样也更加说明了request
必需要在response
以前访问。
而后任务被交给了主队列(毕竟开发者有可能利用response
进行UI
的更新),能够看到在这里并无对response
进行序列化,而是初始化了一个DefaultDataResponse
类的对象,服务器
DefaultDataResponse
是用来保存self.request
、self.response
、self.delegate.data
、self.delegate.error
、self.timeline
、self.delegate.metrics
属性,并把初始化的DefaultDataResponse
对象返回给completionHandler
闭包。(有点相似于Model
,通常来讲,在swift
中,若是只是为了保存数据,那么应该把这个类设计成struct
。struct
是值传递,所以对数据的操做更安全。除了定义须要保存的数据属性后,必须设计一个符合要求的构造函数。), 闭包
小总结:app
request
(该响应来源于那个请求)response
(服务器返回的响应)data
(响应数据)error
(在请求中可能发生的错误)timeline
(请求的时间轴封装)_metrics
(包含了请求和响应的统计信息)这些数据都不是由response
来建立的,它只有使用权。也就是说response
只是一个数据的保存信息者,把各类数据化零为整返回给用户。函数
在Alamofire
中把Request
分为了4类:post
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.request
、
self.response
、
self.delegate.data
、
result
、
self.timeline
,
self.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
信息。
若是我想把请求的结果序列化成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
在其方法内部是直接调用了
response
的序列化方法,那么也就是和
response
同样,把数据序列化为
Data
类型也就是
Result
。
这里传入的序列化器responseSerializer
的参数是DataRequest.dataResponseSerializer()
,下面来看一下dataResponseSerializer()
:
DataResponseSerializer
类型的序列化器,
DataResponseSerializer
这个类前面已经介绍过,它是用来保存序列化函数的,关键在于
Request.serializeResponseData
,
.success(validData)
或者
.failure(error信息)
。
注解:emptyDataStatusCodes
HTTP response code
是
204
或者
205
,就表示
Data
为
nil
.
关于responseString
、responseJSON
、responsePropertyList
在内部是如何实现的,在这里就不一一列出来了,基本和responseData
的套路同样,有兴趣的大佬能够借助源码去看一下。
实际上这个response并非咱们常见的那种response,它只是一个保存内容的载体,它把request
、response
、data
、error
、timeline
、_metrics
这些数据所有收集整合起来,放到本身身上,而后一块儿返回给用户,这样用户在外面能够拿到他想要的任何数据,这是多么牛X的处理方式。