所以你Array
包含两种类型的元素。这是一个很好的Type1OrType2
问题示例。对于这种类型的情况,可以考虑使用enum
with 关联类型。对于您的情况,您需要一个具有&Codable
自定义实现的枚举init(from:) throws
func encode(to:) throws
enum DogOrTurtle: Codable {
case dog(Dog)
case turtle(Turtle)
struct Dog: Codable {
let name: String
let breed: String
}
struct Turtle: Codable {
let color: String
let eats: String
}
}
extension DogOrTurtle {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
// First try to decode as a Dog, if this fails then try another
self = try .dog(container.decode(Dog.self))
} catch {
do {
// Try to decode as a Turtle, if this fails too, you have a type mismatch
self = try .turtle(container.decode(Turtle.self))
} catch {
// throw type mismatch error
throw DecodingError.typeMismatch(DogOrTurtle.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded payload conflicts with expected type, (Dog or Turtle)") )
}
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .dog(let dog):
try container.encode(dog)
case .turtle(let turtle):
try container.encode(turtle)
}
}
}
使用这种方法,您无需担心数组中Dog
or的顺序。Turtle
元素可以以任何顺序和任何数字出现。
用法:(虽然我故意在第三个索引处移动了狗)
let jsonData = """
[
{
"color": "green",
"eats": "lettuce"
},
{
"color": "brown",
"eats": "spinach"
},
{
"name": "Spot",
"breed": "dalmation"
},
{
"color": "yellow",
"eats": "cucumbers"
}
]
""".data(using: .utf8)!
do {
let array = try JSONDecoder().decode([DogOrTurtle].self, from: jsonData)
array.forEach { (dogOrTurtle) in
switch dogOrTurtle {
case .dog(let dog):
print(dog)
case .turtle(let turtle):
print(turtle)
}
}
} catch {
print(error)
}