equest(urlString).validate().responseJSON { response in debugPrint(response) }
一旦OAuth2Handler
为SessionManager
被应用与adapter
和retrier
,他将会通过自动恢复access token来处理一个非法的access token error,并且根据失败的顺序来重试所有失败的请求。(如果需要让他们按照创建的时间顺序来执行,可以使用他们的task identifier来排序)
上面这个例子仅仅检查了401
响应码,不是演示如何检查一个非法的access token error。在实际开发应用中,我们想要检查realm
和www-authenticate
header响应,虽然这取决于OAuth2的实现。
还有一个要重点注意的是,这个认证系统可以在多个session manager之间共享。例如,可以在同一个Web服务集合使用default
和ephemeral
会话配置。上面这个例子可以在多个session manager间共享一个oauthHandler
实例,来管理一个恢复流程。
自定义响应序列化
Alamofire为data、strings、JSON和Property List提供了内置的响应序列化:
Alamofire.request(...).responseData { (resp: DataResponse<Data>) in ... } Alamofire.request(...).responseString { (resp: DataResponse<String>) in ... } Alamofire.request(...).responseJSON { (resp: DataResponse<Any>) in ... } Alamofire.request(...).responsePropertyList { resp: DataResponse<Any>) in ... }
这些响应包装了反序列化的值(Data, String, Any)或者error (network, validation errors),以及元数据 (URL Request, HTTP headers, status code, metrics, ...)。
我们可以有多个方法来自定义所有响应元素:
- 响应映射
- 处理错误
- 创建一个自定义的响应序列化器
- 泛型响应对象序列化
响应映射
响应映射是自定义响应最简单的方式。它转换响应的值,同时保留最终错误和元数据。例如,我们可以把一个json响应DataResponse<Any>
转换为一个保存应用模型的的响应,例如DataResponse<User>
。使用DataResponse.map
来进行响应映射:
Alamofire.request("https://example.com/users/mattt").responseJSON { (response: DataResponse<Any>) in let userResponse = response.map { json in
当转换可能会抛出错误时,使用flatMap
方法:
Alamofire.request("https://example.com/users/mattt").responseJSON { response in let userResponse = response.flatMap { json in try User(json: json) } }
响应映射非常适合自定义completion handler:
@discardableResult
func loadUser(completionHandler: @escaping (DataResponse<User>) -> Void) -> Alamofire.DataRequest {
return Alamofire.request("https://example.com/users/mattt").responseJSON { response in let userResponse = response.flatMap { json in try User(json: json) } completionHandler(userResponse) } } loadUser { response in if let user = userResponse.value { print("User: { username: \(user.username), name: \(user.name) }") } }
上面代码中loadUser
方法被@discardableResult
标记,意思是调用loadUser
方法可以不接收它的返回值;也可以用_
来忽略返回值。
当 map/flatMap 闭包会产生比较大的数据量时,要保证这个闭包在子线程中执行:
@discardableResult
func loadUser(completionHandler: @escaping (DataResponse<User>) -> Void) -> Alamofire.DataRequest {
let utilityQueue = DispatchQueue.global(qos: .utility) return Alamofire.request("https://example.com/users/mattt").responseJSON(queue: utilityQueue) { response in let userResponse = response.flatMap { json in try User(json: json) } DispatchQueue.main.async { completionHandler(userResponse) } } }
map
和flatMap
也可以用于下载响应。
处理错误
在实现自定义响应序列化器或者对象序列化方法前,思考如何处理所有可能出现的错误是非常重要的。有两个方法:1)传递未修改的错误,在响应时间处理;2)把所有的错误封装在一个Error
类型中。
例如,下面是等会要用用到的后端错误:
enum BackendError: Error { case network(error: Error)