如何使用 Decodable 协议将此 JSON 转换为 Swift 结构?
How do I convert this JSON into a Swift structure using the Decodable protocol?
注意:我已经看过这个问题了-> 但是它没有解释如何Encode/Decode枚举
这是我想要的结构:
struct MyStruct: Decodable {
let count: PostType
}
enum PostType: Decodable {
case fast(value: Int, value2: Int)
case slow(string: String, string2: String)
}
现在我知道我希望我的结构看起来如何,问题是:
- 我不知道
init
函数在 PostType
枚举中应该是什么样子。
我使用下面的代码帮助我快速构建JSON。
let jsonData = """
{
"count": {
"fast" :
{
"value": 4,
"value2": 5
}
}
}
""".data(using: .utf8)!
// Decoding
do {
let decoder = JSONDecoder()
let response = try decoder.decode(MyStruct.self, from: jsonData)
print(response)
} catch {
print(error)
}
谁能帮我解决这个问题?
Edit1 我的 JSON 看起来像这样
{
"count": {
"fast" :
{
"value": 4,
"value2": 5
}
}
}
init
在 PostType enum
中应该是什么样子?
由于具有关联类型的 enum
不匹配任何 JSON 类型,您需要更多的手工操作并编写自定义映射。
以下代码包含三个选项。
- 以大小写为键的字典和以参数标签为键的包含字典
- 将每个关联值编码/解码为单独的键/值对
- 使用任意键对数组中的所有关联值进行编码/解码。
首先enum一定不能符合Codable
enum PostType {
case fast(value: Int, value2: Int)
case middle(bool: Bool)
case slow(string: String, string2: String)
}
案例fast
使用数组,middle
使用子字典,slow
单独的键/值对。
然后声明MyStruct
结构,采用Codable
并声明type
struct MyStruct : Codable {
var type : PostType
此解决方案需要自定义键
enum CodingKeys: String, CodingKey {
case value, string, string2, middle
}
encode
方法 switch
用于案例并创建适当的类型
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch type {
case .fast(let value, let value2) :
try container.encode([value, value2], forKey: .value)
case .slow(let string, let string2) :
try container.encode(string, forKey: .string)
try container.encode(string2, forKey: .string2)
case .middle(let bool):
try container.encode(["bool" : bool], forKey: .middle)
}
}
在decode
方法中可以通过传递的键来区分大小写,确保它们是唯一的。
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let allKeys = values.allKeys
if allKeys.contains(.middle) {
let value = try values.decode([String:Bool].self, forKey: .middle)
type = PostType.middle(bool: value["bool"]!)
} else if allKeys.contains(.value) {
let value = try values.decode([Int].self, forKey: .value)
type = PostType.fast(value: value[0], value2: value[1])
} else {
let string = try values.decode(String.self, forKey: .string)
let string2 = try values.decode(String.self, forKey: .string2)
type = PostType.slow(string: string, string2: string2)
}
}
}
虽然有些键是硬编码的,但第一个选项似乎是最合适的。
最后一个使用它的例子:
let jsonString = "[{\"value\": [2, 6]}, {\"string\" : \"foo\", \"string2\" : \"bar\"}, {\"middle\" : {\"bool\" : true}}]"
let jsonData = jsonString.data(using: .utf8)!
do {
let decoded = try JSONDecoder().decode([MyStruct].self, from: jsonData)
print("decoded:", decoded)
let newEncoded = try JSONEncoder().encode(decoded)
print("re-encoded:", String(data: newEncoded, encoding: .utf8)!)
} catch {
print(error)
}
注意:我已经看过这个问题了->
这是我想要的结构:
struct MyStruct: Decodable {
let count: PostType
}
enum PostType: Decodable {
case fast(value: Int, value2: Int)
case slow(string: String, string2: String)
}
现在我知道我希望我的结构看起来如何,问题是:
- 我不知道
init
函数在PostType
枚举中应该是什么样子。
我使用下面的代码帮助我快速构建JSON。
let jsonData = """
{
"count": {
"fast" :
{
"value": 4,
"value2": 5
}
}
}
""".data(using: .utf8)!
// Decoding
do {
let decoder = JSONDecoder()
let response = try decoder.decode(MyStruct.self, from: jsonData)
print(response)
} catch {
print(error)
}
谁能帮我解决这个问题?
Edit1 我的 JSON 看起来像这样
{
"count": {
"fast" :
{
"value": 4,
"value2": 5
}
}
}
init
在 PostType enum
中应该是什么样子?
由于具有关联类型的 enum
不匹配任何 JSON 类型,您需要更多的手工操作并编写自定义映射。
以下代码包含三个选项。
- 以大小写为键的字典和以参数标签为键的包含字典
- 将每个关联值编码/解码为单独的键/值对
- 使用任意键对数组中的所有关联值进行编码/解码。
首先enum一定不能符合Codable
enum PostType {
case fast(value: Int, value2: Int)
case middle(bool: Bool)
case slow(string: String, string2: String)
}
案例fast
使用数组,middle
使用子字典,slow
单独的键/值对。
然后声明MyStruct
结构,采用Codable
并声明type
struct MyStruct : Codable {
var type : PostType
此解决方案需要自定义键
enum CodingKeys: String, CodingKey {
case value, string, string2, middle
}
encode
方法 switch
用于案例并创建适当的类型
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch type {
case .fast(let value, let value2) :
try container.encode([value, value2], forKey: .value)
case .slow(let string, let string2) :
try container.encode(string, forKey: .string)
try container.encode(string2, forKey: .string2)
case .middle(let bool):
try container.encode(["bool" : bool], forKey: .middle)
}
}
在decode
方法中可以通过传递的键来区分大小写,确保它们是唯一的。
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let allKeys = values.allKeys
if allKeys.contains(.middle) {
let value = try values.decode([String:Bool].self, forKey: .middle)
type = PostType.middle(bool: value["bool"]!)
} else if allKeys.contains(.value) {
let value = try values.decode([Int].self, forKey: .value)
type = PostType.fast(value: value[0], value2: value[1])
} else {
let string = try values.decode(String.self, forKey: .string)
let string2 = try values.decode(String.self, forKey: .string2)
type = PostType.slow(string: string, string2: string2)
}
}
}
虽然有些键是硬编码的,但第一个选项似乎是最合适的。
最后一个使用它的例子:
let jsonString = "[{\"value\": [2, 6]}, {\"string\" : \"foo\", \"string2\" : \"bar\"}, {\"middle\" : {\"bool\" : true}}]"
let jsonData = jsonString.data(using: .utf8)!
do {
let decoded = try JSONDecoder().decode([MyStruct].self, from: jsonData)
print("decoded:", decoded)
let newEncoded = try JSONEncoder().encode(decoded)
print("re-encoded:", String(data: newEncoded, encoding: .utf8)!)
} catch {
print(error)
}