0

Been learning SwiftData and ran into a hiccup. Let's say I have to data types User and Job

@Model
class User: Identifiable {
    var id = UUID().uuidString
    var name: String
    var jobs = [Job]()
    
    init(name: String) {
        self.name = name
        self.jobs = jobs
    }
}
@Model
class Job: Identifiable {
    var id = UUID().uuidString
    var name: String
    var user: User?
    
    init(name: String, user: User? = nil) {
        self.name = name
        self.user = user
    }
}

Now, I have a TabView with 2 tabs. One is PeopleView with a list of people and the other is the JobsView with a list of jobs. My idea is to add Users and then assign them a Job, from a list. Jobs would also be added

List of Users List of Jobs

Tapping on a name in a list of people, I get this menu, which lists all available jobs.

Jobs menu

When I choose one, it gets assigned to that person, which is expected. Now, since @Model are a class, selecting the same job for a different person, reassigns that job to the second person and it gets removed from the first person jobs array. This is due to @Model being a class and that is fine, but...

On the other hand, if I add a new instance of a job to a person, so they could all have a same job (task), the array of jobs in the second tab also gets an additional job with the same name. Seems like adding a job to a person.jobs array, also adds it to database in the array of Jobs.

Duplicated jobs

Does Querying jobs aggregates all possible jobs from all people in the database? How can I have only those jobs I added in the Jobs tab? @Query var jobs: [Job]

  • I tried both with appending the Job from a query directly into a person.jobs array (which resulted in reassigning the job to a new person and deleting from the previous person)
person.jobs.append(job)
try? ctx.save()
  • and making a new instance of a job from a query and appending it to person.jobs (which resulted in duplicating jobs in a Jobs list)
let copy = Job(name: job.name)
person.jobs.append(copy)
try? ctx.save()
5
  • 1
    stackoverflow.com/questions/70483227/… Commented Nov 14 at 19:45
  • 1
    Yes you need a many-to-many relationship (two array properties) Commented Nov 14 at 21:11
  • Yes, that did the trick :) And after thinking some more about it, it only makes sense. Well, you live and you learn :D
    – Yoorque
    Commented Nov 14 at 21:46
  • If you found a solution you should either add an answer that shows the code or update your post to include (separately) the needed code. This will benefit anyone that may land on this looking for a similar solution.
    – Andrei G.
    Commented Nov 14 at 22:20
  • Note, @Model class already conforms to Identifiable, there is no need for yet another id, like you have. Commented Nov 14 at 23:07

2 Answers 2

0

The solution was to make sure there is a many-to-many relationship between the two.

@Model
class Job: Identifiable {
  var id = UUID().uuidString
  var name: String
  var users: [User] = [] <——- change

  init(name: String) {
    self.name = name
}

}

-2

First you need a relationship, e.g.

@Model
final class AnimalCategory {
    @Attribute(.unique) var name: String
    // `.cascade` tells SwiftData to delete all animals contained in the 
    // category when deleting it.
    @Relationship(deleteRule: .cascade, inverse: \Animal.category)
    var animals = [Animal]()
    
    init(name: String) {
        self.name = name
    }
}

https://developer.apple.com/documentation/swiftdata/defining-data-relationships-with-enumerations-and-model-classes

Then you need another query, e.g.

struct ArticleView: View {
    
    @Environment(\.modelContext) private var modelContext    
    @Query private var articleStates: [ArticleState]


    let article: Article
    
    init(article: Article) {
        self.article = article
        _articleStates = Query(filter: #Predicate { $0.articleID == article.id } )
    }
    
    var body: some View {
        ... // SwiftUI view that depends on query data.
    }
}

https://developer.apple.com/tutorials/app-dev-training/swiftdata-sorting-and-filtering

1
  • Thanks for answering. The previous comment did the trick. I needed many-to-many relationship.
    – Yoorque
    Commented Nov 14 at 21:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.