skip to Main Content

I am trying to make a sample app which uses SwiftData to keep track of sports goals. I have a struct: Team which has values id (UUID), name (string), score (int), and editing (bool). I have a SwiftData model class which contains the values id (UUID), teams ([Team]), pro (Boolean). Normally, the class works fine without having the teams array in the CounterModel class, but as soon as I add var teams: [Team] to the class, I get the following errors:

  • Type 'CounterModel' does not conform to protocol 'PersistentModel'
  • No exact matches in call to instance method 'getValue'
  • No exact matches in call to instance method 'setValue'

The class conforms to Identifiable, Hashable. The struct also conforms to these protocols. Conforming both to Codable does not make the error go away.
Here is my code if needed:

import Foundation
import SwiftData

@Model
class CounterModel: Identifiable, Hashable {
    @Attribute(.unique) var id = UUID()
    var teams: [Team]
    var pro: Bool
    
    init(teams: [Team], pro: Bool) {
        self.teams = teams
        self.pro = pro
    }
    func toTeamArr() -> [Team] {
        return teams
    }
    
}
struct Team: Identifiable, Hashable {
    var id: UUID = UUID()
    var name: String
    var score: Int
    var editing: Bool = false
}

edit: I have also tried putting the Team struct inside of the class. Same error.
edit2: following a suggestion by a reply, here is the updated code:

import Foundation
import SwiftData

@Model
class CounterModel: Identifiable, Hashable {
    @Attribute(.unique) var id = UUID()
    @Relationship(.cascade) var teams: [Team]
    var pro: Bool
    
    init(teams: [Team], pro: Bool) {
        self.teams = teams
        self.pro = pro
    }
    func toTeamArr() -> [Team] {
        return teams
    }
}

@Model
class Team: Identifiable, Hashable {
    @Attribute(.unique) var id: UUID = UUID()
    var name: String
    var score: Int
    @Transient var editing: Bool = false
    
    init(name: String, score: Int, editing: Bool = false) {
        self.name = name
        self.score = score
        self.editing = editing
    }
}

Now, there are only 2 errors produced:

  • Type ‘CounterModel’ does not conform to protocol ‘PersistentModel’
  • Type ‘Team’ does not conform to protocol ‘PersistentModel’

Edit 3: Upon extracting the models into a separate Xcode project, it builds fine. When I bring the rest of my code into the project, it stops working. Will investigate further.
Okay. It seems to be an issue with passing the data from the @Query modifier into different views. Upon removing the parameters for the CounterModel data model from the views, the app compiled fine. I’m assuming, and hoping that this is a bug. For now, I’ll just query the data separately in the views. Thank you all for your help! I have submitted feedback on the issue, just in case: FB12338703

2

Answers


  1. Chosen as BEST ANSWER

    Okay. It seems to be an issue with passing the data from the @Query modifier into different views. Upon removing the parameters for the CounterModel data model from the views, the app compiled fine. I'm assuming, and hoping that this is a bug. For now, I'll just query the data separately in the views. Thank you all for your help!


  2. There are two changes you need to make to your model classes.

    The first, is to change Team to a class and make it an @Model
    The second change is to tell SwiftData that teams is a reference to another SwiftData entity using the @Relationship decorator.

    class CounterModel: Identifiable, Hashable {
        @Attribute(.unique) var id = UUID()
        @Relationship(.cascade) var teams: [Team]
        var pro: Bool
        
        init(teams: [Team], pro: Bool) {
            self.teams = teams
            self.pro = pro
        }
        func toTeamArr() -> [Team] {
            return teams
        }
        
    }
    
    @Model
    class Team: Identifiable, Hashable {
        @Attribute(.unique) var id: UUID = UUID()
        var name: String
        var score: Int
        @Transient var editing: Bool = false
    }
    

    The .cascade argument to @Relationship tells SwiftData to delete all of the referenced Team objects if the CounterModel object is deleted.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search