I am building a calendar-like app that renders calendars month by month. The program contains several calendars (let's say 2 for the purpose of the question, calendar A and B) that store independent data. I have a @Published
variable selectedCalendar
defined in an ObservableObject
class called EnvironmentClass()
that determines which calendar the various Views should render.
class EnvironmentClass: ObservableObject {
@Published var calendars: OrderedDictionary<String,CalendarClass> = CalendarClass.sampleData
@Published var date = Date() // Today's date
@Published var selectedCalendar = "A"
}
here date
holds todays date and calendars
hold data about the calendars.
In the home View there is a menu View from which one can change calendars, called CalendarsView
. The issue is the following: if I run the app I see a calendar month for which all date cells belong to "A"
(found with a print statement). When I change calendar to "B"
from CalendarsView
, what I see is that only a part of the date cells changes to "B"
, while some of them remain "A"
. By debugging with print statement I found out that, after receiving a new information in env
, the app starts to render the date cells slightly before changing actually calendar in env.selectedCalendar
.
Few extra info found from debugging:
- The number of cells that remain "A" changes every time I launch the app. Sometimes it's just a couple, other times many.
- The ForEach that renders the date cells (see
calendarGrid
below) whenenv.selectedCalendar
changes to"B"
does it in order but skips some (randomly). Those cells are the ones that will actually change to "B" and are rendered in order right afterenv.selectedCalendar
changes. - If I press a second time the button that changes the View to
"B"
, the month I see is correct in the sense that all the cells belong to"B"
. At this point, if I press"A"
the same problem happens (with the same cells).
It looks like the information env.selectedCalendar = "B"
is injected in calendarGrid
(see below) with a little bit of delay. Is this the problem? If so, how does one fix it?
I attach the code for CalendarsView
and calendarGrid
.
import SwiftUI
struct CalendarsView: View {
@EnvironmentObject var env: EnvironmentClass
var body: some View {
ScrollView (.horizontal, showsIndicators: true) {
HStack (spacing: 30) {
ForEach(env.calendars.keys, id: \.self) {index in
Button(action: {
env.selectedCalendar = index
}) {
Text(index)
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}.padding(.horizontal, 35).padding(.bottom,50)
}
}
}
(here env.calendars.keys
contains "A"
and "B"
).
The actual calendar View is rendered using a LazyVGrid
var calendarGrid: some View {
VStack{
let columnLayout: [GridItem] = Array(repeating: GridItem(), count: 7)
let firstDayOfMonth = CalendarHelper().firstOfMonth(env.date)
let startingSpaces = CalendarHelper().weekDay(CalendarHelper().minusDay(firstDayOfMonth))
let currentMonth: [Date?] = Array(repeating: nil, count: startingSpaces) + CalendarHelper().daysInMonthArray(env.date)
// I use currentMonth with few nil values to address the indentation of the weekdays
// (if the month starts on Friday, I skip startingSpaces=4 date cells).
LazyVGrid(columns: columnLayout) {
ForEach(currentMonth.indices, id: \.self) { index in
if (currentMonth[index] != nil) {
DateCell(day: currentMonth[index]!)
.environmentObject(env)
}
else {
Text("")
}
}
}
}.padding(.horizontal, 25)
}
Any help is very appreciated.