Swift Codable with dynamic keys

血红的双手。 提交于 2019-11-27 03:38:04

问题


I have JSON structure as:

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

I tried to parse it like this:

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")
    }
}

But I can get result for only one value (2018-06-06). I have multiple dates here that I want to parse. Is this possible?


回答1:


Assuming you left out the { and } that would surround this block and are required for this to be valid JSON, the following is the simplest solution to getting things parsed, you really don't need to deal with CodingKey at all since your names match the keys in the JSON, so the synthesized CodingKey will work just fine:

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)

The key is that the outer JSON is a JSON Object (dictionary/map) with a single key periods The value of that key is another map of arrays. Just break it down like that and everything falls out pretty much automatically.




回答2:


Ok, so I figured it out like this:

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
    }
}

As result I got dictionary like this: ["2018-06-06": [Inner]] where key is this Date String, and value Inner.




回答3:


I think the JSON shall be appended with { at the beginning and } at the end in order to be valid JSON, then you can easily extract periods with code like that:

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


来源:https://stackoverflow.com/questions/50713638/swift-codable-with-dynamic-keys

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!