admin管理员组

文章数量:1336632

I have a SwiftData @Query which gives me a array of Event objects. Due to the nature of the object (e.g. dynamic distance calculations) I filter the events manually using function.

This works fine for any changes in the objects, and they are shown directly in the SwiftUI List. But If I add an object the List is not updated (as it is created from the filtered list, not directly from the @Quary).

Is there a way to subscribe to the @Quary to get a notification (or to pass the state on) so the data is refreshed? This is the relevant code, the data variable contains the data sorted by day and filtered using a normal function. FilterManager is an observable object, which notifies if the filter parameters change.

@State var data: [Date:[Event]] = [:]
@Query(sort: \Event.startTime) private var events: [Event]

List {
   ForEach(Array(data.keys).sorted(by: <), id: \.self) { day in
         Section(header: Text(day,format: Date.FormatStyle()
              .year(.defaultDigits)
              .month(.abbreviated)
              .day(.twoDigits)
              .weekday(.abbreviated)).font(.footnote)) {
                   ForEach(data[day]!) { item in
                          [...]
                   }
         }
 }.onAppear(){
    data = filterManager.sortedEvents(events: filterManager.filteredEvents(events: events))
 }.onReceive(filterManager.objectWillChange){
    data = filterManager.sortedEvents(events: filterManager.filteredEvents(events: events))
 }

I have a SwiftData @Query which gives me a array of Event objects. Due to the nature of the object (e.g. dynamic distance calculations) I filter the events manually using function.

This works fine for any changes in the objects, and they are shown directly in the SwiftUI List. But If I add an object the List is not updated (as it is created from the filtered list, not directly from the @Quary).

Is there a way to subscribe to the @Quary to get a notification (or to pass the state on) so the data is refreshed? This is the relevant code, the data variable contains the data sorted by day and filtered using a normal function. FilterManager is an observable object, which notifies if the filter parameters change.

@State var data: [Date:[Event]] = [:]
@Query(sort: \Event.startTime) private var events: [Event]

List {
   ForEach(Array(data.keys).sorted(by: <), id: \.self) { day in
         Section(header: Text(day,format: Date.FormatStyle()
              .year(.defaultDigits)
              .month(.abbreviated)
              .day(.twoDigits)
              .weekday(.abbreviated)).font(.footnote)) {
                   ForEach(data[day]!) { item in
                          [...]
                   }
         }
 }.onAppear(){
    data = filterManager.sortedEvents(events: filterManager.filteredEvents(events: events))
 }.onReceive(filterManager.objectWillChange){
    data = filterManager.sortedEvents(events: filterManager.filteredEvents(events: events))
 }
Share Improve this question asked Nov 20, 2024 at 22:16 Luuk D. JansenLuuk D. Jansen 4,5088 gold badges49 silver badges95 bronze badges 6
  • you could try using a computed property, such as var data: [Date:[Event]] { filterManager.sortedEvents(events: filterManager.filteredEvents(events: events)) } instead of @State var data... – workingdog support Ukraine Commented Nov 20, 2024 at 23:10
  • That did the trick, and it works perfect now – Luuk D. Jansen Commented Nov 20, 2024 at 23:29
  • turned the comment into an answer. – workingdog support Ukraine Commented Nov 20, 2024 at 23:33
  • Just be aware that a computed property that relies on a @Query property will be called a lot so this could lead to performance issues depending on what is being done in those sort and filter functions and of course on how much data you have. – Joakim Danielson Commented Nov 21, 2024 at 10:18
  • id: \.self will probably cause a crash since its not a valid keypath to unique identifier. Also onReceive isn't right, SwiftUI already monitors observable objects automatically. – malhal Commented Nov 21, 2024 at 14:58
 |  Show 1 more comment

2 Answers 2

Reset to default 1

Use a computed property (that depends on events), such as

var data: [Date:[Event]] { 
   filterManager.sortedEvents(events: filterManager.filteredEvents(events: events)) 
} 

instead of

@State var data: [Date:[Event]] = [:]

Assuming you add Event objects which trigger a refresh of the Query, you should be able to observe it:

.onChange(of: events.count) {
    data = filterManager.sortedEvents(events: filterManager.filteredEvents(events: events))
}

本文标签: swiftuiNotifying a change in SwiftData queryStack Overflow