swiftswiftuicodable

How to conform an ObservableObject to the Codable protocols?


In SwiftUI beta 5, Apple introduced the @Published annotation. This annotation is currently blocking this class from conforming to the Codable protocols.

How can I conform to these protocols so I can encode and decode this class to JSON? You can ignore the image property for now.

class Meal: ObservableObject, Identifiable, Codable {

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case ingredients
        case numberOfPeople
    }

    var id = Globals.generateRandomId()
    @Published var name: String = "" { didSet { isInputValid() } }
    @Published var image = Image("addImage")
    @Published var ingredients: [Ingredient] = [] { didSet { isInputValid() } }
    @Published var numberOfPeople: Int = 2
    @Published var validInput = false

    func isInputValid() {
        if name != "" && ingredients.count > 0 {
            validInput = true
        }
    }
}


Solution

  • Add the init() and encode() methods to your class:

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
    
        id = try values.decode(Int.self, forKey: .id)
        name = try values.decode(String.self, forKey: .name)
        ingredients = try values.decode([Ingredient].self, forKey: .ingredients)
        numberOfPeople = try values.decode(Int.self, forKey: .numberOfPeople)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(ingredients, forKey: .ingredients)
        try container.encode(numberOfPeople, forKey: .numberOfPeople)
    }