Swift: Decode different objects from JSON array
- 3 minsDecoding different objects from JSON array in Swift
Problem: Decode objects from an array with different objects
struct Car: Decodable {
let manufacturer: String
let model: String
}
struct Person: Decodable {
let name: String
let lastName: String
}
let json = """
{
"information_array": [
{
"manufacturer": "Audi",
"model": "A3"
},
{
"name": "John",
"lastName": "Doe"
},
{
"weatherType": "windy",
"degrees": "10",
"degreesType": "celcius"
}
]
}
"""
Solution
struct OptionalDecodable<T: Decodable>: Decodable {
let base: T?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.base = try? container.decode(T.self)
}
}
extension Decoder {
func decodeObject<T: Decodable>() throws -> T {
let container = try singleValueContainer()
guard let object = try container.decode([OptionalDecodable<T>].self).compactMap({ $0.base }).first else {
let context = DecodingError.Context(codingPath: container.codingPath,
debugDescription: "Value for type \(type(of: T.self)) not found")
throw DecodingError.valueNotFound(T.self, context)
}
return object
}
func decodeObjects<T: Decodable>() throws -> [T] {
let container = try singleValueContainer()
let objects = try container.decode([OptionalDecodable<T>].self).compactMap({ $0.base })
return objects
}
}
struct ContainerObject: Decodable {
let car: Car
let person: Person
enum CodingKeys: String, CodingKey {
case infoArray = "information_array"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let arrayDecoder = try container.superDecoder(forKey: .infoArray)
self.car = try arrayDecoder.decodeObject()
self.person = try arrayDecoder.decodeObject()
}
}