【发布时间】:2019-03-20 00:21:27
【问题描述】:
我目前正在处理一个 API 尚未准备好的项目。所以有时某些属性的类型会发生变化。例如我有这个结构:
struct Animal: Codable {
var tag: Int?
var name: String?
var type: String?
var birthday: Date?
}
对于这个 json:
{
"tag": 12,
"name": "Dog",
"type": "TYPE1"
}
但在开发中,json 会变成这样:
{
"tag": "ANIMAL",
"name": "Dog",
"type": 1
}
所以我在解码器和 nil 对象 中遇到了一些 类型不匹配 错误。为了防止解码器使整个对象失败,我实现了一个自定义 init 并为任何未知属性设置了 nil ,它就像魅力一样工作(注意:我会处理这些稍后更改,这仅适用于计划外和临时更改):
#if DEBUG
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
tag = (try? container.decodeIfPresent(Int.self, forKey: .tag)) ?? nil
name = (try? container.decodeIfPresent(String.self, forKey: .name)) ?? nil
type = (try? container.decodeIfPresent(String.self, forKey: .type)) ?? nil
birthday = (try? container.decodeIfPresent(Date.self, forKey: .birthday)) ?? nil
}
#endif
但是对于较大的类和结构,我必须手动编写任何属性,这需要时间,更重要的是,有时我错过了要设置的属性!
那么有没有办法枚举所有属性并设置它们? 我知道我可以从容器中获取所有密钥,但不知道如何设置它的相应属性:
for key in container.allKeys {
self.<#corresponding_property#> = (try? container.decodeIfPresent(<#corresponding_type#>.self, forKey: key)) ?? nil
}
谢谢
【问题讨论】:
-
Codable的全部意义在于提供一种类型安全和静态的方式来将 Swift 类型编码/解码到 JSON。您正在寻找的动态代码在 Swift/Codable 中是不可能的。此外,您不应通过此自定义init来掩盖客户端数据模型和 API 之间的不匹配,而实际上应该解决这些问题。此外,使用自动生成用于发出 API 请求/响应的代码的 API 响应设计工具(例如 Swagger)可以让您避免此类错误。 -
问题是你的值的 type 不断变化:有时
tag是一个字符串,有时它是一个整数。您将需要比 Optional 方法更多的东西;它处理某物是否存在,而不是它是否具有正确的类型。您需要一个 StringOrInteger 类型,如下所述:stackoverflow.com/questions/47215260/… 或者,正如已经建议的那样,完全放弃 Decodable ,因为如果 API 要像这样跳舞是不合适的。 -
是的,我知道,但是当没有 API 文档并且它正在开发中时,我们不希望在调试模式下出现这么多的崩溃。实际上我把初始化器放在 #if DEBUG ... #endif @DávidPásztor
-
如果您无法控制 API,要么等待其开发完成,要么在其实现波动很大时使用模拟服务器。另一方面,如果您可以控制 API 设计,请让其开发人员使用更适合解决此类问题的工具,如前所述。此外,最好将开发中的此类错误捕获为崩溃,而不是使用您的方法掩盖它们并让错误意外泄漏到生产中。
-
谢谢@DávidPásztor。但问题是关于所有属性的枚举并为它们分配一个值,而不是关于这个用例。我更新了问题的标题以进行更多说明。