jsonswiftencodable

How to convert an array of multiple object types to JSON without missing any object attribute in Swift?


In my iOS Swift project, I need to convert objects to JSON.

I have one simple class:

class Car : Encodable
{
    var brand: String

    init(brand: String)
    {
        self.brand = brand
    }
}

and one subclass:

class SUVCar : Car
{
    var weight: Int

    init(_ weight: Int)
    {
        self.weight = weight
        super.init(brand: "MyBrand")
    }
}

I use the following generic function to convert objects and arrays to JSON:

func toJSON<T : Encodable>(_ object: T) -> String?
{
    do
    {
        let jsonEncoder = JSONEncoder()
        let jsonEncode = try jsonEncoder.encode(object)
        return String(data: jsonEncode, encoding: .utf8)
    }
    catch
    {
        return nil
    }
}

Now let's say I want to convert the following variable to JSON:

var arrayOfCars: Array<Car> = []
arrayOfCars.append(SUVCar(1700))
arrayOfCars.append(SUVCar(1650))

I use Array<Car> as the type for that array because there are other types of cars in that array. I just made it simpler here for the sake of readability.

So here is what I did:

let json = toJSON(arrayOfCars)

But for some reason, when converting to JSON, the weight attribute of SUVCar is ignored, even though arrayOfCars contains SUVCar objects, and I get a JSON that looks like this:

[{brand: "MyBrand"}, {brand: "MyBrand"}]

So how can I get the weight attribute of SUVCar in my JSON? What did I miss?

Thanks.


Solution

  • class SUVCar: Car
    {
        enum SUVCarKeys: CodingKey {
            case weight
        }
        var weight: Int
    
        init(_ weight: Int)
        {
            self.weight = weight
            super.init(brand: "MyBrand")
        }
        
        override func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: SUVCarKeys.self)
            try container.encode(weight, forKey: .weight)
            try super.encode(to: encoder)
        }
    }
    

    If you augment the subclass's implementation of encode then you can add in additional properties