gpt4 book ai didi

Swift Codable - 解析可以包含不同数据类型的 JSON 数组

转载 作者:搜寻专家 更新时间:2023-10-31 22:04:43 25 4
gpt4 key购买 nike

我正在尝试解析一个 JSON 数组,它可以是

{
"config_data": [
{
"name": "illuminate",
"config_title": "Blink"
},
{
"name": "shoot",
"config_title": "Fire"
}
]
}

也可以是以下类型

{
"config_data": [
"illuminate",
"shoot"
]
}

甚至

{
"config_data": [
25,
100
]
}

为了使用 JSONDecoder 解析它,我创建了一个结构,如下所示 -

Struct Model: Codable {
var config_data: [Any]?

enum CodingKeys: String, CodingKey {
case config_data = "config_data"
}

init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
config_data = try values.decode([Any].self, forKey: .config_data)
}
}

但这行不通,因为 Any 不确认可解码协议(protocol)。这可能是什么解决方案。该数组可以包含任何类型的数据

最佳答案

我用了quicktype推断 config_data 的类型,它为您的对象、字符串和整数值建议了一个具有不同大小写的枚举:

struct ConfigData {
let configData: [ConfigDatumElement]
}

enum ConfigDatumElement {
case configDatumClass(ConfigDatumClass)
case integer(Int)
case string(String)
}

struct ConfigDatumClass {
let name, configTitle: String
}

这是 the complete code example .解码 enum 有点棘手,但 quicktype 可以帮助您:

// To parse the JSON, add this file to your project and do:
//
// let configData = try? JSONDecoder().decode(ConfigData.self, from: jsonData)

import Foundation

struct ConfigData: Codable {
let configData: [ConfigDatumElement]

enum CodingKeys: String, CodingKey {
case configData = "config_data"
}
}

enum ConfigDatumElement: Codable {
case configDatumClass(ConfigDatumClass)
case integer(Int)
case string(String)

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(Int.self) {
self = .integer(x)
return
}
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
if let x = try? container.decode(ConfigDatumClass.self) {
self = .configDatumClass(x)
return
}
throw DecodingError.typeMismatch(ConfigDatumElement.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ConfigDatumElement"))
}

func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .configDatumClass(let x):
try container.encode(x)
case .integer(let x):
try container.encode(x)
case .string(let x):
try container.encode(x)
}
}
}

struct ConfigDatumClass: Codable {
let name, configTitle: String

enum CodingKeys: String, CodingKey {
case name
case configTitle = "config_title"
}
}

使用 enum 很好,因为这样可以获得最大的类型安全性。其他答案似乎失去了这一点。

使用 quicktype 的 convenience initializers 选项,一个工作代码示例是:

let data = try ConfigData("""
{
"config_data": [
{
"name": "illuminate",
"config_title": "Blink"
},
{
"name": "shoot",
"config_title": "Fire"
},
"illuminate",
"shoot",
25,
100
]
}
""")

for item in data.configData {
switch item {
case .configDatumClass(let d):
print("It's a class:", d)
case .integer(let i):
print("It's an int:", i)
case .string(let s):
print("It's a string:", s)
}
}

这打印:

It's a class: ConfigDatumClass(name: "illuminate", configTitle: "Blink")
It's a class: ConfigDatumClass(name: "shoot", configTitle: "Fire")
It's a string: illuminate
It's a string: shoot
It's an int: 25
It's an int: 100

关于Swift Codable - 解析可以包含不同数据类型的 JSON 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48314724/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com