I have two models like these:
@Model
class Post {
...
@Relationship(inverse: \Comment.post) var comments: [Comment]?
}
@Model
class Comment {
...
var post: Post
}
And in one of my views I use a query like the one below where I show a list of posts and their comments count:
struct PostsList: View {
@Query var posts: [Post]
var body: some View {
List {
ForEach(posts) { post in
PostListItem(post: post)
}
}
}
}
struct PostListItem: View {
@State var post: Post
var body: some View {
Text("\(post.title)")
Text("\(post.comments?.count ?? 0) comments")
}
}
When I insert a new comment with a given post, and then I go back to the view which shows the list of posts and their comments count, the count is not updated for the post I used unless I relaunch the app.
Is there a way to make SwiftData reload a given query, not when the entities returned changed, but when a related one did?
It turns out the issue was simply in the way I pass the single Post
to PostListItem
.
Given that I am not an expert in SwiftUI, the only two way I found until now to solve this issue are the following.
Solution 1: Remove the subview PostListItem
and render each Post
directly in the List.
struct PostsList: View {
@Query var posts: [Post]
var body: some View {
List {
ForEach(posts) { post in
Text("\(post.title)")
Text("\(post.comments?.count ?? 0) comments")
}
}
}
}
Solution 2: Wrap the Post
in a view model annotated with @Observable
and use it as state in PostListItem
.
struct PostsList: View {
@Query var posts: [Post]
var body: some View {
List {
ForEach(posts) { post in
PostListItem(model: PostListItemModel(post: post))
}
}
}
}
@Observable
class PostListItemModel {
var post: Post
init(post: Post) {
self.post = post
}
}
struct PostListItem: View {
var model: PostListItemModel
var body: some View {
Text("\(model.post.title)")
Text("\(model.post.comments?.count ?? 0) comments")
}
}