Search code examples
iosencodingswiftuidecodable

Type 'Model' does not conform to protocol 'Decodable'/Encodable


I can't figure out how I can fix this error.

If I remove @Published, it compiles everything correct but then I can't see the data in a cell in real time. Reading I saw that I need the var with @Published

import SwiftUI
import Combine

class TimeModel: Codable, Identifiable, ObservableObject {
    
    @Published var id: UUID = UUID()
    @Published var nome : String
    @Published var time : String
    
    func aggiornaUI() {
        DispatchQueue.main.async {
            self.objectWillChange.send()
        }
    }

    init(nome: String, time: String) {
        self.nome = nome
        self.time = time
    }
    
}

Update: ok thanks I check now but the error remain

        HStack {
            Text("\(timeString(from: Int(TimeInterval(remainingSeconds))))")
                .onReceive(timer) { _ in
                    if isCounting && remainingSeconds > 0 {
                        remainingSeconds -= 1
                    }
                }

error:

Instance method 'onReceive(_:perform:)' requires that 'TimeModel' conform to 'Publisher'


Solution

  • A @Published property with type, let's say, String, are of type Published<String>. And apparently, that type is not Codable.

    You can solve this by writing custom encode and decode functions. That's not difficult; it's only some extra lines of code. Please see the documentation on Codable for some examples.

    Here is an example for your case:

    class TimeModel: Codable, Identifiable, ObservableObject {
        @Published var id: UUID = UUID()
        @Published var nome : String
        @Published var time : String
        
        func aggiornaUI() {
            DispatchQueue.main.async {
                self.objectWillChange.send()
            }
        }
        
        init(nome: String, time: String) {
            self.nome = nome
            self.time = time
        }
        
        enum CodingKeys: String, CodingKey {
            case id
            case nome
            case time
        }
        
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(id, forKey: .id)
            try container.encode(nome, forKey: .nome)
            try container.encode(time, forKey: .time)
        }
        
        required init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(UUID.self, forKey: .id)
            nome = try container.decode(String.self, forKey: .nome)
            time = try container.decode(String.self, forKey: .time)
        }
    }
    

    This should work, but I can't really test it because I don't know the rest of your code.