问题描述
我遇到了一个 API,我必须重用我现有的 Codable 模型之一来解析 JSON。但是,“service_name”键在新 API 中被命名为“name”。我向我的 android 开发人员询问了他如何使用相同的模型解析该 JSON。他告诉我,在用于在 android 中解析的 GSON 库中也有相同的支持。代码如下
@Serializedname(value = "service_name",alternate = ["name"])
我想知道这是否可以在 Codable 中以直接的方式实现。我知道这可以通过变通办法来实现。但是 Swift Codable 是否支持开箱即用的功能
我的要求:
API JSON 响应 1
API 2 JSON 响应
我正在使用如下模型进行解析
// MARK: - CustomerOtherServiceResponseModel
struct CustomerOtherServiceResponseModel:Decodable {
let name:String
let externalLink:String?
let type:ServiceType
}
是否可以对两个 API 使用相同的模型?。编码键只能映射到一个属性,对吗?。或者有没有其他方法可以使用相同的模型来做同样的事情。
解决方法
这可以通过实现自定义 init(from:)
来解决,我们首先尝试解码“name”键,如果这不起作用,我们尝试使用“service_name”键。
对于第二个键,我们使用与我们合成的不同的 CodingKey 枚举创建一个新的容器对象。
struct Service: Codable {
let name: String
let id: Int
let type: String
enum OtherApiKeys: String,CodingKey {
case name = "service_name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self,forKey: .id)
if let value = try? container.decodeIfPresent(String.self,forKey: .name) {
name = value
} else {
let otherContainer = try decoder.container(keyedBy: OtherApiKeys.self)
name = try otherContainer.decode(String.self,forKey: .name)
}
type = try container.decode(String.self,forKey: .type)
}
}
由于您发布的 json 和 struct 代码不匹配,因此我在这里使用了自己的 struct 和 json,但应该很容易翻译。下面是我的测试数据和代码
let data1 = """
{
"id": 157,"name": "Some name","type": "hair"
}
""".data(using: .utf8)!
let data2 = """
{
"id": 158,"service_name": "Some name","type": "hair"
}
""".data(using: .utf8)!
do {
let decoder = JSONDecoder()
for data in [data1,data2] {
let result = try decoder.decode(Service.self,from: data)
print(result)
}
} catch {
print(error)
}