Ios 在同一标记下具有两个结构的JSON可解码
我有一个json:Ios 在同一标记下具有两个结构的JSON可解码,ios,json,swift5,decodable,Ios,Json,Swift5,Decodable,我有一个json: { "stuff": [ { "type":"car", "object":{ "a":66, "b":66, "c":66 }}, { "type":"house", "object":{ "d":66, "e":66, "f":66 }}, { "type":"car", "object":{ "a":66, "b":66, "c":66 }} ]} 正如您可以看到的,对于car和house,有不同的对象结构,但都在
{ "stuff": [
{
"type":"car",
"object":{
"a":66,
"b":66,
"c":66 }},
{
"type":"house",
"object":{
"d":66,
"e":66,
"f":66 }},
{
"type":"car",
"object":{
"a":66,
"b":66,
"c":66 }}
]}
正如您可以看到的,对于car和house,有不同的对象结构,但都在标记对象下
如果一个人最终得到这样的东西,那将是理想的
struct StuffItem: Decodable {
let type: TheType
let car: Car
let house: House
}
是否有一些可编码、快速的方法来处理此问题?我认为最快速的方法是使用关联类型的枚举
这是有效的JSON
let jsonString = """
{ "stuff": [
{
"type":"car",
"object":{
"a":66,
"b":66,
"c":66
}
},{
"type":"house",
"object":{
"d":66,
"e":66,
"f":66
}
},{
"type":"car",
"object":{
"a":66,
"b":66,
"c":66
}
}
]}
"""
这些是结构
struct Root : Decodable {
let stuff : [Object]
}
enum Type : String, Decodable { case car, house }
struct Car : Decodable {
let a, b, c : Int
}
struct House : Decodable {
let d, e, f : Int
}
enum Object : Decodable {
case house(House), car(Car)
private enum CodingKeys : String, CodingKey { case type, object }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(Type.self, forKey: .type)
switch type {
case .car:
let carData = try container.decode(Car.self, forKey: .object)
self = .car(carData)
case .house:
let houseData = try container.decode(House.self, forKey: .object)
self = .house(houseData)
}
}
}
以及解码JSON的代码
do {
let result = try JSONDecoder().decode(Root.self, from: Data(jsonString.utf8))
let objects = result.stuff
for object in objects {
switch object {
case .car(let car): print(car)
case .house(let house): print(house)
}
}
} catch {
print(error)
}
您可以通过使用枚举来处理多种情况—只需定义您的类型,给出代码将帮助您通过使用带有枚举的Struct modal来解析JSON
// MARK: - Welcome
struct Welcome: Codable {
let stuff: [Stuff]
}
// MARK: - Stuff
struct Stuff: Codable {
let type: String
let object: Object
}
// MARK: - Object
struct Object: Codable {
let a, b, c, d: Int?
let e, f: Int?
}
enum Type: String {
case car
case house
}
func fetchResponse() {
do {
let jsonString = "your json string"
let data = Data(jsonString.utf8)
let result = try JSONDecoder().decode(Welcome.self, from: data)
let objects = result.stuff
let carObjects = objects.filter{$0.type == Type.car.rawValue}
print("Its car array: \(carObjects)")// if you need filters car object then use this
let houseObjects = objects.filter{$0.type == Type.house.rawValue}// if you need filters house object then use this
print("Its house array: \(houseObjects)")
// or you check in loop also
objects.forEach { (stuff) in
switch stuff.type {
case Type.car.rawValue:
print("Its car object")
case Type.house.rawValue:
print("Its house object")
default:
print("Also you can set your one case in `default`")
break
}
}
} catch {
print(error.localizedDescription)
}
}
另一种解释是:
由于没有太多的解释,这里是@vadian解释的另一个例子:
1.在Swift中,使用枚举而不是结构来实现“灵活类型”。
2.然后需要为“item”和“type”使用解析器。
2.解析,然后切换到解码,并设置正确的类型。
对于上面的JSON,您需要
struct YourFeed: Decodable {
let stuff: [Item]
}
每件物品都可以是汽车或房子
struct Car: Decodable { ... }
struct House: Decodable { ... }
所以这些都很简单
现在是第二项。它可以是多种类型
在Swift中,使用枚举而不是结构来实现“灵活类型”。
接下来,只需将其镜像到原始枚举中,该枚举将用于解析类型字段。你可以叫它任何东西,我刚刚叫它Parse
// the relevant key strings for parsing the "type" field:
private enum Parse: String, Decodable {
case car
case house
}
接下来,查看顶部的原始JSON。每个项目有两个字段,类型和对象。这里是原始枚举。再说一次,你可以叫它任何东西,我刚才在这里叫它Keys
// we're decoding an item, what are the top-level tags in item?
private enum Keys: String, CodingKey {
// so, these are just the two fields in item from the json
case type
case object
}
有一个枚举来解析“item”级别,还有一个枚举来解析“type”。
最后,编写项的初始值设定项。只需解码的顶级和类型
init(from decoder: Decoder) throws {
// parse the top level
let c = try decoder.container(keyedBy: Keys.self)
// and parse the 'type' field
let t = try c.decode(Parse.self, forKey: .type)
。。。你完成了。使用相关类解码数据,并将Item enum对象设置为适当的类型
解析这些,然后切换到解码/设置枚举。
这是一个完整的过程:
enum Item: Decodable {
case car(Car)
case house(House)
// the relevant key strings for parsing the 'type' field:
private enum Parse: String, Decodable {
case car
case house
}
// the top-level tags in 'item':
private enum Keys: String, CodingKey {
case type
case object
}
init(from decoder: Decoder) throws {
// parse the top level
let c = try decoder.container(keyedBy: Keys.self)
// parse the 'type' field
let t = try c.decode(Parse.self, forKey: .type)
// we're done, switch to
// decode (using the relevant decoder), and become the relevant type:
switch t {
case .car:
let d = try c.decode(Car.self, forKey: .object)
self = .car(d)
case .house:
let d = try c.decode(House.self, forKey: .object)
self = .house(d)
}
}
}
此json不是JSONAL json键必须用双引号括起来。这是必需的。它仍然不是有效的JSON。缺少许多逗号和右大括号。发布伪JSON并没有真正的帮助。不,你没有。天哪!!我很抱歉!修正!:对于任何阅读本文的人来说,理解这里的一个关键点是对象不再是结构,它必须是枚举;这是一个很好的解释,谢谢。我不知道如何做到这一点,令人惊讶的是,它没有在更多的地方解释得更清楚!途中赏金
// we're done, so depending on which of the types it is,
// decode (using the relevant decoder), and become the relevant type:
switch t {
case .car:
let d = try c.decode(Car.self, forKey: .object)
self = .car(d)
case .house:
let d = try c.decode(House.self, forKey: .object)
self = .house(d)
}
}
}
enum Item: Decodable {
case car(Car)
case house(House)
// the relevant key strings for parsing the 'type' field:
private enum Parse: String, Decodable {
case car
case house
}
// the top-level tags in 'item':
private enum Keys: String, CodingKey {
case type
case object
}
init(from decoder: Decoder) throws {
// parse the top level
let c = try decoder.container(keyedBy: Keys.self)
// parse the 'type' field
let t = try c.decode(Parse.self, forKey: .type)
// we're done, switch to
// decode (using the relevant decoder), and become the relevant type:
switch t {
case .car:
let d = try c.decode(Car.self, forKey: .object)
self = .car(d)
case .house:
let d = try c.decode(House.self, forKey: .object)
self = .house(d)
}
}
}