Home > database >  Fetching the latest entity from a relationship in Swift Core Data
Fetching the latest entity from a relationship in Swift Core Data

Time:08-27

Im trying to find the best way to get the latest entity from a relationship with swift and core data.

For example I have a Conversation with many Messages:

Conversation Entity:
id = 1, name = "Test"
Message Entity:
id = 1, body = "Test", conversation = 1
id = 2, body = "Test", conversation = 1

In my SwiftUI View I have this FetchRequest:

@FetchRequest(sortDescriptors: []) var conversations: FetchedResults<Conversation>

What would be the best way to access the relation and get the latest result while looping over the conversations in View like this:

List(conversations) { conversation in
    Text(conversation.name ?? "")
    Text(conversation.messages.latest.body ?? "") // <--- Trying to do something like this
}

CodePudding user response:

The best way is to store the data you need in the entity you are fetching. So in your case make a latestMessageBody property on the conversation entity. Apple provide derived attributes to automate this.

It's a common mistake to think of Core Data as a relational database, instead just think of it as a way to persist what you see on screen and design your entities based on how you want to fetch and display them. If you are making too many fetches on one screen then its time to redesign the entities.

I.e. you wouldn't want to fetch the latest message for all the converstations you want to show that is too many fetches. And you don't want to load in all the messages for every conversation just to find the latest, that has too high memory overhead. This is why Core Data offers denormalisation via the derived attributes feature.

Another point is @FetchRequest (which is powered by NSFetchedResultsController by the way) only tracks changes to the entity that is currently fetched. So if you reach into relations to show data, that view won't update when the related object changes. You can work around this by passing the object into another View marked with @ObservedObject however that doesn't work for a 1-to-many relation.

There is a neat trick using entity inheritance to allow a NSFetchedResultsController to work on multiple entities however I don't think that is suitable for this use case.

  • Related