Search code examples
iosjsonswiftcodablecomputed-properties

How to use computed property in a codable struct (swift)


I've created a "codable" struct to serialize a data set and encode it to Json. Everything is working great except the computed properties don't show in the json string. How can I include computed properties during the encode phase.

Ex:

struct SolidObject:Codable{

    var height:Double                      = 0
    var width:Double                       = 0
    var length:Double                      = 0

    var volume:Double {
        get{
            return height * width * length
        }
    }
}

var solidObject = SolidObject()
solidObject.height = 10.2
solidObject.width = 7.3
solidObject.length = 5.0

let jsonEncoder = JSONEncoder()
do {
    let jsonData = try jsonEncoder.encode(solidObject)
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print(jsonString)
} catch {
    print(error)
}

prints out "{"width":7.2999999999999998,"length":5,"height":10.199999999999999}"

I am also curious about having 7.29999.. instead of 7.3 but my main question is "how can I include "volume" to this json string too"?


Solution

  • You need to manually encode/decode instead of letting the automated stuff do it for you. This works as expected in a Swift playground.

    struct SolidObject: Codable {
    
        var height:Double                      = 0
        var width:Double                       = 0
        var length:Double                      = 0
    
        var volume:Double {
            get{
                return height * width * length
            }
        }
    
        enum CodingKeys: String, CodingKey {
            case height
            case width
            case length
    
            case volume
        }
    
        init() { }
    
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            height = try values.decode(Double.self, forKey: .height)
            width = try values.decode(Double.self, forKey: .width)
            length = try values.decode(Double.self, forKey: .length)
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(height, forKey: .height)
            try container.encode(width, forKey: .width)
            try container.encode(length, forKey: .length)
    
            try container.encode(volume, forKey: .volume)
        }
    
    }
    
    var solidObject = SolidObject()
    solidObject.height = 10.2
    solidObject.width = 7.3
    solidObject.length = 5.0
    
    let jsonEncoder = JSONEncoder()
    do {
        let jsonData = try jsonEncoder.encode(solidObject)
        let jsonString = String(data: jsonData, encoding: .utf8)!
        print(jsonString)
    } catch {
        print(error)
    }