Overview
I give you a bit of context. I have an app that shows events for a certain date in a weekly view. Check the screenshot to have an idea of the UI. The part on top is an horizontal calendar that shows one week at a time. Every time the visible week changes, the data source should be updated.
Considering this, I’ve found difficult to use the @Query wrapper. The interaction are simple: when a user tap on a row (that represents a day), a sheet will be open with the possibility to add an event with a start date and an end date and a Save button. If there’s no event on that day, a new one is created and assigned to the entry. If present, the event object is directly modified.
The main issue is that when an event is modified the change is not reflected in the view (WeekdayRowView). More generally, I’m not sure the approach I chose is the right one, considering I’m not using the @Query wrapper. If you have suggestions, I’m all ears to learn how to do the right things.
Code
I’ve included some code. I cut off all the useless code, as it would be significantly longer than this. I hope this is enough to understand the situation.
The data source is an array of WeekdayEntry objects, this is the code:
struct WeekdayEntry: Identifiable, Equatable, Hashable {
let id = UUID()
let date: Date
var event: Event?
mutating func update(event: Event?) {
self.event = event
}
static func ==(lhs: WeekdayEntry, rhs: WeekdayEntry) -> Bool {
return lhs.id == rhs.id && lhs.event == rhs.event
}
}
Event is a SwiftData model. In my main view the structure is this:
struct EventsListView: View {
@State private var dataSource: [WeekdayEntry] = []
@State private var visibleWeek: Week
@State private var showingSheet: Bool = false
@State private var selectedEntryIndex: Int = 0
private let sheetHeight: CGFloat = 200
...
var body: some View {
HorizontalWeekView(visibleWeek: $visibleWeek)
headerView
.padding(.top, 10)
ScrollView {
ForEach(Array(dataSource.enumerated()), id: \.1) { (index, entry) in
WeekdayRowView(date: entry.date, event: $dataSource[index].event)
.padding(.horizontal)
.padding(.vertical, 5)
.simultaneousGesture(
TapGesture().onEnded {
print("tapped row for date \(entry.date.toString())")
self.showingSheet.toggle()
self.selectedEntryIndex = index
}
)
}
}
.padding(.top, 5)
.scrollBounceBehavior(.basedOnSize)
.scrollIndicators(.hidden)
}
.sheet(isPresented: $showingSheet) {
EventEditView(date: dataSource[selectedEntryIndex].date, event: $dataSource[selectedEntryIndex].event)
.onSave({ date, from, to in
self.showingSheet.toggle()
})
.padding(.horizontal)
.presentationDetents([.height(sheetHeight)])
.presentationCornerRadius(20)
Spacer()
}
.onAppear {
print("events list onAppear")
if dataSource.isEmpty {
reloadDataSource()
}
}
private func reloadDataSource() {
dataSource = []
visibleWeek.dates.sorted{ $0 < $1 }.forEach { dataSource.append(WeekdayEntry(date: $0, event: DatabaseService.shared.fetchEvent(forDate: $0))) }
}
private func reloadEventsForVisibleWeek() {
for index in 0..<dataSource.count {
let date = dataSource[index].date
let updatedEntry = WeekdayEntry(date: date, event: DatabaseService.shared.fetchEvent(forDate: date))
dataSource[index] = updatedEntry
}
}
}
This is the basic structure of WeekdayRowView:
struct WeekdayRowView: View {
let date: Date
@Binding var event: Event?
@State var from: Date = Date.now
@State var to: Date = Date.now + 1.hours
...
}
This is the basic structure of EventEditView:
struct EventEditView: View {
let date: Date
@Binding var event: Event?
@State var from: Date = Date.now
@State var to: Date = Date.now + 1.hours
...
var body: some View {
...
Button(action: {
print("saving...")
if let event {
event.date = date
event.from = from
event.to = to
} else {
let event = Event(date: date, from: from, to: to)
DatabaseService.shared.saveEvent(event)
self.event = event
}
onSave(date, from, to)
...
}
}





