带有动态键的 Swift Codable

Posted

技术标签:

【中文标题】带有动态键的 Swift Codable【英文标题】:Swift Codable with dynamic keys 【发布时间】:2018-11-15 17:46:02 【问题描述】:

我有 JSON 结构 为:

"periods": 
    "2018-06-07": [
      
        "firstName": "Test1",
        "lastName": "Test1"
      
    ],
    "2018-06-06": [
      
        "firstName": "Test1",
        "lastName": "Test1"
      
    ]

我试着像这样解析它:

public struct Schedule: Codable 
    public let periods: Periods


public struct Periods: Codable 
    public let unknown: [Inner]

    public struct Inner: Codable 
        public let firstName: String
        public let lastName: String
    

    private struct CustomCodingKeys: CodingKey 
        var stringValue: String
        init?(stringValue: String) 
            self.stringValue = stringValue
        

        var intValue: Int?
        init?(intValue: Int) 
            return nil
        
    

    public init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CustomCodingKeys.self)
        self.unknown = try container.decode([Inner].self, forKey: CustomCodingKeys(stringValue: "2018-06-06")
    

但我只能得到一个值(2018-06-06) 的结果。我在这里有多个要解析的日期。这可能吗?

【问题讨论】:

你可以手动解析 或者我使用app.quicktype.io快速生成我的结构体 【参考方案1】:

好的,所以我是这样想的:

public struct Schedule: Codable 
    public let periods: Periods


public struct Periods: Codable 
    public var innerArray: [String: [Inner]]
    
    public struct Inner: Codable 
        public let firstName: String
        public let lastName: String
    
    
    private struct CustomCodingKeys: CodingKey 
        var stringValue: String
        init?(stringValue: String) 
            self.stringValue = stringValue
        
        var intValue: Int?
        init?(intValue: Int) 
            return nil
        
    
    public init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CustomCodingKeys.self)
        
        self.innerArray = [String: [Inner]]()
        for key in container.allKeys 
            let value = try container.decode([Inner].self, forKey: CustomCodingKeys(stringValue: key.stringValue)!)
            self.innerArray[key.stringValue] = value
        
    

结果我得到了这样的字典:["2018-06-06": [Inner]] 其中键是这个日期字符串,值是 Inner。

【讨论】:

亲爱的 Masta 什么是 CustomCodingKeys? 我想维护字典插入顺序..如何实现? 如何获取所有 2018-06-06 密钥?【参考方案2】:

我认为 JSON 应在开头附加 并在末尾附加 以便成为有效的 JSON,然后您可以使用以下代码轻松提取句点:

struct Period: Decodable 
    let firstName: String, lastName: String


let schedule = try? JSONDecoder().decode([String:[String:[Period]]].self, from: jsonData!)
let periods = schedule?.values.first?.values

【讨论】:

【参考方案3】:

假设您省略了围绕此块的 并且这是有效 JSON 所必需的,以下是解析内容的最简单解决方案,您真的不需要处理CodingKey 因为你的名字与 JSON 中的键匹配,所以合成的 CodingKey 可以正常工作:

public struct Schedule: Codable 
    public let periods : [String:[Inner]]


public struct Inner: Codable 
    public let firstName: String
    public let lastName: String


let schedule = try? JSONDecoder().decode(Schedule.self, from: json)

print(schedule?.periods.keys)

print(schedule?.periods["2018-06-07"]?[0].lastName)

关键是外部 JSON 是一个 JSON 对象(字典/映射),具有单个键 periods 该键的值是另一个数组映射。像这样分解它,一切都会自动消失。

【讨论】:

以上是关于带有动态键的 Swift Codable的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中编写一个带有排序键的漂亮打印 JSON 对象

动态查找带有主键的表

带有动态键的打字稿通用函数

如何使用带有动态对象键的打字稿

如何使用 Swift 将具有两个不同键的两个值存储到数组或字典中? [关闭]

在 Swift 3 中使用带有动态 URL 的 AVAudioPlayer 导致线程错误