JSON 可解码,同一标签下有两个结构
Decodable for JSON with two structs under the same tag
我有这个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”有不同 "object" 结构,但都在标签 "object".
下
如果最后得到类似
的东西就太理想了
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 模态来解析 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{[=10=].type == Type.car.rawValue}
print("Its car array: \(carObjects)")// if you need filters car object then use this
let houseObjects = objects.filter{[=10=].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、中使用enum代替struct实现'flexible type'.
2。然后,您需要 'item' 和 'type'.
的解析器
2。解析,然后切换到解码,并设置正确的类型。
所以对于上面的JSON,你有
struct YourFeed: Decodable {
let stuff: [Item]
}
每个项目可以是汽车或房子。
struct Car: Decodable { ... }
struct House: Decodable { ... }
所以这些很简单。
现在 Item
。可以不止一种。
在Swift,使用enum代替struct实现'flexible type'.
// in Swift, an "enum" is basically a "struct" which can have a flexible type,
// so here we have enum Item rather than struct Item:
enum Item: Decodable {
// so this thing, Item, can be one of these two types:
case car(Car)
case house(House)
接下来,只需将其镜像到原始枚举中,该枚举将用于解析 "type" 字段。 (你可以随便叫它,我只是叫它 "Parse"。)
// the relevant key strings for parsing the "type" field:
private enum Parse: String, Decodable {
case car
case house
}
接下来,看原文JSON置顶。每个 "item" 有两个字段,"type" 和 "object"。它们在原始枚举中。 (同样,您可以将其命名为任何名称,我在这里将其命名为 "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'。
最后,为"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)
... 大功告成。解码数据(使用相关的 class),并将 "Item" 枚举对象设置为适当的类型。
解析那些,然后切换到解码/设置枚举。
// 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)
}
}
}
我有这个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”有不同 "object" 结构,但都在标签 "object".
下如果最后得到类似
的东西就太理想了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 模态来解析 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{[=10=].type == Type.car.rawValue}
print("Its car array: \(carObjects)")// if you need filters car object then use this
let houseObjects = objects.filter{[=10=].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、中使用enum代替struct实现'flexible type'.
2。然后,您需要 'item' 和 'type'.
的解析器2。解析,然后切换到解码,并设置正确的类型。
所以对于上面的JSON,你有
struct YourFeed: Decodable {
let stuff: [Item]
}
每个项目可以是汽车或房子。
struct Car: Decodable { ... }
struct House: Decodable { ... }
所以这些很简单。
现在 Item
。可以不止一种。
在Swift,使用enum代替struct实现'flexible type'.
// in Swift, an "enum" is basically a "struct" which can have a flexible type,
// so here we have enum Item rather than struct Item:
enum Item: Decodable {
// so this thing, Item, can be one of these two types:
case car(Car)
case house(House)
接下来,只需将其镜像到原始枚举中,该枚举将用于解析 "type" 字段。 (你可以随便叫它,我只是叫它 "Parse"。)
// the relevant key strings for parsing the "type" field:
private enum Parse: String, Decodable {
case car
case house
}
接下来,看原文JSON置顶。每个 "item" 有两个字段,"type" 和 "object"。它们在原始枚举中。 (同样,您可以将其命名为任何名称,我在这里将其命名为 "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'。
最后,为"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)
... 大功告成。解码数据(使用相关的 class),并将 "Item" 枚举对象设置为适当的类型。
解析那些,然后切换到解码/设置枚举。
// 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)
}
}
}