NEW: Subscribe to Hacking with Swift+ and accelerate your learning! >>

Decoding JSON consisting of sub-classes

Forums > Swift

Dear all,

I have run into the following issue: I am trying to decode a json file that consists of different sub-classes with different information degrees. Let me explain with a simplified example:

Class

class Vehicle: Codable {
    var currentlyDrives: Bool
    var speed: Double

    init(drives: Bool, speed: Double) {
        self.currentlyDrives = drives
        self.speed = speed
    }
}

class Car: Vehicle {
    var numberOfPassengers: Int

    init(drives: Bool, speed: Double, numPax: Int) {
        self.numberOfPassengers = numPax
        super.init(drives: drives, speed: speed)
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        numberOfPassengers = try container.decode(Int.self, forKey: .numberOfPassengers)
        try super.init(from: decoder)
    }

    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(numberOfPassengers, forKey: .numberOfPassengers)
        try super.encode(to: encoder)
    }

    enum CodingKeys: String, CodingKey {
        case numberOfPassengers
    }
}

If I am creating instances of both "Vehicles" and "Cars" and putting everything in an array, I have no problem encoding to a proper JSON file (including all properties of Cars if we have a car and only properties of vehicles if we have a vehicle (see below)).

let car = Car(drives: true, speed: 123, numPax: 5)
let bike = Vehicle(drives: true, speed: 12)

var array = [Vehicle]()
array.append(car)
array.append(bike)

let encoded = try! JSONEncoder().encode(array)
print(String(data: encoded, encoding: .utf8)!)

The above prints a proper JSON as follows with car having the additional "numberOfPassengers" property:

[{"currentlyDrives":true,"numberOfPassengers":5,"speed":123},{"currentlyDrives":true,"speed":12}]

When decoding I am able to read back all Vehicles without a problem. However what I would like to achieve is reading back a vehicle as a car if it is one (i.e. being able to read "numberOfPassengers".

Do you have any idea how this would be achievable?

Many thanks in advance and best regards, Julian

   

What I want to add: when I have an array of Cars, I habe no problem reading back an array of Cars with all properties.

But what I really want to achieve is encoding an array of vehicles (which can be car OR vehicle) and then being able to cast as the actual type.

i hope this makes sense, otherwise happy to provide another example.

Any ideas are highly appreciated.

Stay healthy!

   

Hacking with Swift is sponsored by Paw

SPONSORED Use Paw to build, test and describe web APIs. Paw has a lightning fast native macOS interface to compose requests, collaborate in real-time on API specs, and generate client code for your applications. You can import and export API definitions.

Discover Paw for Mac

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

Not logged in

Log in
 

Link copied to your pasteboard.