【问题标题】:Swift Codable with dynamic keys带有动态键的 Swift Codable
【发布时间】: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快速生成我的结构体

标签: json swift swift4 codable


【解决方案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 该键的值是另一个数组映射。像这样分解它,一切都会自动消失。

    【讨论】:

      猜你喜欢
      • 2021-05-24
      • 2020-07-28
      • 2019-05-12
      • 1970-01-01
      • 2018-12-13
      • 2018-05-23
      • 2018-09-07
      相关资源
      最近更新 更多