由于复杂的原因,我发现自己在违背以下原则Codable:在解码 json 对象时,我想将子对象保留在extra“just as json”键下,存储为[String: Any]字典,但[String: Any](当然)不是Decodable。有什么办法可以做到这一点吗?
第一个答案当然是“不”。我的回答是“我需要”:我需要对数据进行两次 Codable传递,其中第一次解码异构对象列表(每个对象都有一个 key name),而第二次传递使用以这些值为键的字典name,并且是正确类型安全的。第一遍不能是类型安全的,因为它在异构列表上操作,但它需要保留第二遍将使用的所有数据。值得庆幸的是,所有异构数据都隐藏在该extra密钥下,但我仍然不知道该怎么做。
(很可能会有一个关于编码相同内容的后续问题,所以如果您碰巧有洞察力,请随时提及。)
您可以创建一个自定义字典Decodable,该字典对值进行解码并将其存储在 an 中Dictionary,然后将此类型用作要在其中存储原始字典的键。
这是可解码的:
struct DictionaryDecodable: Decodable {
let dictionary : [String: Any]
private struct Key : CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder: Decoder) throws {
let con = try decoder.container(keyedBy: Key.self)
var dict = [String: Any]()
for key in con.allKeys {
if let value = try? con.decode(String.self, forKey:key) {
dict[key.stringValue] = value
} else if let value = try? con.decode(Int.self, forKey:key) {
dict[key.stringValue] = value
} else if let value = try? con.decode(Double.self, forKey:key) {
dict[key.stringValue] = value
} else if let value = try? con.decode(Bool.self, forKey:key) {
dict[key.stringValue] = value
} else if let data = try? con.decode(DictionaryDecodable.self, forKey:key) {
dict[key.stringValue] = data.dictionary
}
}
self.dictionary = dict
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以使用此结构来解码字典,如下所示:
struct Test: Decodable {
let name: String
let data: [String: Any]
enum Keys: String, CodingKey {
case name
case data
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Keys.self)
name = try container.decode(String.self, forKey: .name)
data = try container.decode(DictionaryDecodable.self, forKey: .data).dictionary // Here use DictionaryDecodable
}
}
Run Code Online (Sandbox Code Playgroud)
我们来测试一下:
let data = """
{
"name": "name",
"data": {
"string": "rt",
"bool": true,
"float": 1.12,
"int": 1,
"dict": {
"test": "String"
}
}
}
"""
let s = try JSONDecoder().decode(Test.self, from: data.data(using: .utf8)!)
print(s.name)
print(s.data)
Run Code Online (Sandbox Code Playgroud)
这是输出:
name
["bool": true, "string": "rt", "int": 1, "float": 1.12, "dict": ["test": "String"]]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1777 次 |
| 最近记录: |