Swift Codable:用未知键解码字典
Swift Codable: decode dictionary with unknown keys
当您知道 JSON 数据的关键格式时,Codable
非常有用。但是,如果您不知道密钥怎么办?我目前正面临这个问题。
通常我希望 JSON 数据像这样返回:
{
"id": "<123>",
"data": [
{
"id": "<id1>",
"event": "<event_type>",
"date": "<date>"
},
{
"id": "<id2>",
"event": "<event_type>",
"date": "<date>"
},
]
}
但这就是我要解码的内容:
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "<date>" } },
{ "<id2>": { "<event>": "<date>" } },
]
}
问题是: 我如何使用 Codable
解码 JSON 密钥是唯一的?我觉得我错过了一些明显的东西。
这就是我希望这样做的,这样我就可以使用 Codable
:
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Any]]]
// MARK: - Decoding
enum CodingKeys: String, CodingKey {
case id = "id"
case data = "data"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
// This throws an error: Ambiguous reference to member 'decode(_:forKey:)'
data = try container.decode([[String: [String: Any]]].self, forKey: .data)
}
}
这会引发错误:Ambiguous reference to member 'decode(_:forKey:)'
对于你完全改变的问题,解决方案非常相似。您的结构只是在数组上方添加了一个额外的层。不需要任何自定义解码,甚至不需要任何 CodingKeys。
请注意,您不能在 Codable 中使用 Any
。
let json="""
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "2019-05-21T16:15:34-0400" } },
{ "<id2>": { "<event>": "2019-07-01T12:15:34-0400" } },
]
}
"""
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Date]]]
}
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode(SampleModel.self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}
原始问题的原始答案。
由于您有一个嵌套字典数组,其中 none 个字典键是固定的,并且由于没有其他字段,您可以将其解码为普通数组。
这是一个例子:
let json="""
[
{ "<id1>": { "<event>": "2019-07-01T12:15:34-0400" } },
{ "<id2>": { "<event>": "2019-05-21T17:15:34-0400" } },
]
"""
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode([[String: [String: Date]]].self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}
Codable
非常有用。但是,如果您不知道密钥怎么办?我目前正面临这个问题。
通常我希望 JSON 数据像这样返回:
{
"id": "<123>",
"data": [
{
"id": "<id1>",
"event": "<event_type>",
"date": "<date>"
},
{
"id": "<id2>",
"event": "<event_type>",
"date": "<date>"
},
]
}
但这就是我要解码的内容:
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "<date>" } },
{ "<id2>": { "<event>": "<date>" } },
]
}
问题是: 我如何使用 Codable
解码 JSON 密钥是唯一的?我觉得我错过了一些明显的东西。
这就是我希望这样做的,这样我就可以使用 Codable
:
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Any]]]
// MARK: - Decoding
enum CodingKeys: String, CodingKey {
case id = "id"
case data = "data"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
// This throws an error: Ambiguous reference to member 'decode(_:forKey:)'
data = try container.decode([[String: [String: Any]]].self, forKey: .data)
}
}
这会引发错误:Ambiguous reference to member 'decode(_:forKey:)'
对于你完全改变的问题,解决方案非常相似。您的结构只是在数组上方添加了一个额外的层。不需要任何自定义解码,甚至不需要任何 CodingKeys。
请注意,您不能在 Codable 中使用 Any
。
let json="""
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "2019-05-21T16:15:34-0400" } },
{ "<id2>": { "<event>": "2019-07-01T12:15:34-0400" } },
]
}
"""
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Date]]]
}
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode(SampleModel.self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}
原始问题的原始答案。
由于您有一个嵌套字典数组,其中 none 个字典键是固定的,并且由于没有其他字段,您可以将其解码为普通数组。
这是一个例子:
let json="""
[
{ "<id1>": { "<event>": "2019-07-01T12:15:34-0400" } },
{ "<id2>": { "<event>": "2019-05-21T17:15:34-0400" } },
]
"""
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode([[String: [String: Date]]].self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}