代码改变世界

自定义 Alamofire 的 response serializer

2019-04-10 16:03  l4y  阅读(866)  评论(0编辑  收藏  举报

Alamofire 的 DataRequest 类针对二进制数据、字符串、json、属性列表提供了一系列方便解析的方法(内部实际上使用的是 Response Serializer),现在我们要针对服务端返回的数据格式定义我们自己的 Response Serializer。

假设服务器返回的数据格式是这样的:

{
    "code": 0,
    "datas": {
        "name": "Jack",
        "age": 13
    },
    "message": ""
}

其中 datas、message 对应的数据可能为空,我们来针对这个格式定义 Response Serializer。

从二进制数据到数据模型,直接使用 Swift 4 内置的 JSONDecoder 进行解析,所以,定义的模型需要遵从 Decodable 协议(下面的代码,我为了偷懒直接写了 Codable)。

struct Response<T: Codable>: Codable {
    let code: Int
    let datas: T?
    let message: String?
}

struct Person: Codable {
    let name: String
    let age: Int
}

extension DataRequest {
    static func customResponseSerializer<T: Codable>(type: T.Type) -> DataResponseSerializer<T> {
        return DataResponseSerializer(serializeResponse: { (request, response, data, error) -> Result<T> in
            guard error == nil else {
                return .failure(error!)
            }
            let result = Request.serializeResponseData(response: response, data: data, error: nil)
            switch result {
            case .success(let validData):
                do {
                    let entity = try JSONDecoder().decode(T.self, from: validData)
                    return .success(entity)
                } catch {
                    return .failure(error)
                }
            case .failure(let error):
                return .failure(error)
            }
        })
    }

    @discardableResult
    func responseCustomObject<T: Codable>(queue: DispatchQueue? = nil,
                                type: T.Type,
                                completion: @escaping (DataResponse<T>) -> Void) -> Self {
        return response(queue: queue, responseSerializer: Alamofire.DataRequest.customResponseSerializer(type: type), completionHandler: completion)
    }
}

使用的时候,这样就好了:

Alamofire.request("http://mall.cnrmall.com/api/app/version_check").responseCustomObject(type: Response<VersionInfo>.self) { (response) in
    switch response.result {
    case .success(let value):
        print(value)
    case .failure(let error):
        print("error: \(error.localizedDescription)")
    }
}