Search code examples
iosswiftswiftuiios17swiftdata

"Cannot Synthesize" -- Why is this class not ready to be declared "@Model" for use with SwiftData?


I am trying to convert the Landmarks app to SwiftData... why isn't this class conforming to codable/decodable? It won't compile but the messages are non-specific:

"Type 'Landmark' does not conform to protocol 'Decodable'" "Type 'Landmark' does not conform to protocol 'Encodable'"

and

In expansion of macro 'Model' here: "Cannot automatically synthesize 'Decodable' because 'any SwiftData.BackingData' does not conform to 'Decodable'"

import Foundation
import SwiftUI
import CoreLocation
import SwiftData

@Model
final class Landmark: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var dezcription: String
    var isFavorite: Bool
    var isFeatured: Bool
    
    var category: Category
    private var coordinates: Coordinates
    private var imageName: String
    
    init(id:Int = Int.random(in: 2000...Int.max), name:String = "", park: String = "", state:String = "", dezcription: String = "", isFavorite: Bool = false, isFeatured:Bool = false, category: Category = Category.mountains, coordinates: Coordinates = Coordinates(latitude: 0, longitude: 0), imageName:String = "umbagog") {
        self.id = id
        self.name = name
        self.park = park
        self.state = state
        self.dezcription = dezcription
        self.isFavorite = isFavorite
        self.isFeatured = isFeatured
        self.category = category
        self.coordinates = coordinates
        self.imageName = imageName
        
    }

    
    enum Category: String, CaseIterable, Codable {
        case lakes = "Lakes"
        case rivers = "Rivers"
        case mountains = "Mountains"
    }

    var image: Image {
        Image(imageName)
    }
    
    
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

PS - I know that the design of this (the random int id... the default location of 0,0) are bad... but that's not the point of the question.

I've tried:

  • Commenting out/isolating potentially problematic types
  • Making sure everything is codable
  • Including all vars in the initializer
  • Reading the dos and donts of declaring a @Model class
  • Making the Image var @Transient (although it is computed anyway so that should not be necessary)
  • Moving the Coordinates struct and Category enum higher in scope (out of this class)
  • Adding a "real" UUID variable that actually is guaranteed unique

Solution

  • Sorry, this is a case where I made a false assumption in my question — That this class needs to be codable.

    The reason the class was marked Codable was because that was the way it was in the original Landmarks app and I didnt think to change it.

    What I didn't realize is that a class marked with @Model does not require any explicit protocols, and in fact should not be marked codable unless one plans on doing some serious surgery as in Sweeper's answer.

    If I simply remove the Codable protocol (and can also remove all other protocols safely), it works.

    I enterpreted the error message as a Swiftdata error when it is just a “normal” error saying “this class is not codable [because of Swiftdata macro]”

    So the other previous answers are appreciated and valid if anyone out there actually has a class they need to be a swift data model and codable, but in my case it was just a false assumption.

    One could say that this renders the question invalid, but that is hindsight and I think this the answer to my question, and the information will be valuable to people with the same misunderstanding.