Итак, ваш Array
содержит два типа элементов.Это хороший пример проблемы Type1OrType2
.Для случаев такого типа вы можете рассмотреть возможность использования enum
со связанным типом.Для вашего случая вам понадобится перечисление 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
или 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)
}