带动态键的Swift Codable

时间:2018-06-06 06:33:51

标签: json swift swift4 codable

我有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)。我在这里有多个日期要解析。这可能吗?

3 个答案:

答案 0 :(得分:3)

假设您遗漏了围绕此块的{}并且这是有效的JSON所必需的,以下是解析内容的最简单的解决方案,你真的不因为你的名字与JSON中的键匹配所以需要处理CodingKey,所以合成的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该键的值是另一个数组映射。就这样打破它,一切都会自动消失。

答案 1 :(得分:2)

好的,所以我想出来就是这样:

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]]其中key是这个Date String,值是Inner。

答案 2 :(得分:0)

我认为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