Swift JSONDecoder 默认替换所有缺失的键?

Posted

技术标签:

【中文标题】Swift JSONDecoder 默认替换所有缺失的键?【英文标题】:Swift JSONDecoder replace all missing keys by default value? 【发布时间】:2022-01-05 06:32:58 【问题描述】:

我想为不值得通过 App Review 的分阶段功能发布、季节性变化、优惠等设置远程配置文件。

我曾经使用\n 分隔的文本文件,但对于多行字符串,这很快就会变得有点尴尬。

我目前正在编写一个小型单例,用于从远程 URL 解析配置文件,而不是为此导入一些像 Firebase 这样臃肿的框架。

然而,我现在面临一个问题:

如果远程 json 包含一个未在我的 Codable 结构中定义的键,一切正常,我仍然会使用所有定义的键获得我的对象。相反,如果 json 缺少结构中定义的键,则 JSONDecoder 无法解码。示例:

    let testJSON = """
"version":1,"includedB":"B","___notIncludedC":"C"
"""

struct DefaultConfiguration : Codable 
    var version = 1
    var includedB = "2"
    var notIncludedC = "3"

我可以通过将 notIncludedC 定义为可选的 String? 来使解码“工作” - 但是这会使解码后的结果为 nil,而不是保持其预定义的默认值。

关于 SO 的所有答案都提到为每个键定义自定义方法,但我更愿意使用“跳过未知并保留值”方法,因为对于大型 JSON,这会带来大量开销代码。

【问题讨论】:

您必须编写自己的解码初始化程序。合成的Decodable 一致性不能满足您的需求,因此您必须自己编写。无论如何,它应该不需要太多代码 将可选属性设为可选是 imo 最直接的解决方案。 【参考方案1】:

正如 cmets 中所述,您必须编写自己的 init(),因为合成的 init() 无法提供您需要的行为:

let testJSON = """
"version":1,"includedB":"B","notIncludedC":"C"
"""

struct DefaultConfiguration : Codable 
    var version = 1
    var includedB = "2"
    var notIncludedC = "3"

    enum CodingKeys: String, CodingKey 
        case version
        case includedB
        case notIncludedC
     

    init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        version = try container.decode(Int.self, forKey: .version)
        includedB = try container.decode(String.self, forKey: .includedB)
        notIncludedC = try container.decodeIfPresent(String.self, forKey: .notIncludedC) ?? "3"
    

【讨论】:

很糟糕,显然没有其他解决方案,感谢您抽出宝贵时间!

以上是关于Swift JSONDecoder 默认替换所有缺失的键?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift 4 中的 JSONDecoder,缺少的键可以使用默认值而不是可选属性吗?

使用 Swift 4 中的 JSONDecoder,缺少的键可以使用默认值而不是可选属性吗?

使用 Swift 4 中的 JSONDecoder,缺少的键可以使用默认值而不是可选属性吗?

Swift 4 JSONDecoder 解码协议类型

Swift - JSONDecoder & Combine 框架问题

Swift - 将类型动态传递给 JSONDecoder