Computed property gets computed infinitely and SwiftUI becomes unresponsive

Hi, I have a computed property in my SwiftUI Todo app that shows the status of the past 4 days - whether the todo was completed or not. For this I have a computed array days that contains the last 4 days including today. Using this array I show the results in checkboxes which is a SwiftUI view. But I have a problem, at midnight when the day changes the app becomes completely unresponsive as this array gets computed again and again infinitely. Only deleting the app and reinstalling it allows it to run normally again, until the next time the day changes when the same thing happens again.
Code Block
var days: [Day] {
var computedDays = [Day]()
let calendar = Calendar.current
var dayIndex = calendar.component(.weekday, from: Date())
let lastFourDays = formatDateForPastFourDays(from: Date())
// considering today is 20th August 2020
// lastFourDays = ["August 20, 2020", "August 19, 2020", "August 18, 2020", "August 17, 2020"]
let daysInitials = ["Su", "M", "T", "W", "Th", "F", "S"]
let checkedDates = computeCheckedDates(lastFourDays)
// checkedDates = [true, false]
let passedDates = computePassedDates(for: checkedDates, dates: lastFourDays)
// passedDates = [false, true, false, false]
for idx in 0..<checkedDates.count {
computedDays.append(Day(id: idx, date: lastFourDays[idx], dayValue: daysInitials[dayIndex - 1], checked: checkedDates[idx], passed: passedDates[idx]))
dayIndex -= 1
if dayIndex == 0 {
dayIndex = 7
}
}
// computedDays = [ToDoApp.Day(id: 0, date: "August 20, 2020", dayValue: "Th", checked: true, passed: false), ToDoApp.Day(id: 1, date: "August 19, 2020", dayValue: "W", checked: false, passed: true)]
return computedDays
}

Code Block
private func computeCheckedDates(_ dates: [String]) -> [Bool] {
var checkedDates: [Bool]
if createdAt != nil {
let calendar = Calendar.current
let daysDiff = calendar.dateComponents([.day], from: calendar.startOfDay(for: createdAt!), to: Date()).day
if daysDiff == 0 {
checkedDates = [false]
} else if daysDiff == 1 {
checkedDates = [false, false]
} else if daysDiff == 2 {
checkedDates = [false, false, false]
} else {
checkedDates = [false, false, false, false]
}
} else {
checkedDates = [false]
}
if completedDates != nil {
for idx in 0..<checkedDates.count {
checkedDates[idx] = completedDates!.contains(dates[idx])
}
}
return checkedDates
}
var createdAt: Date? {
return habit.createdAt ?? Date()
}
var completedDates: [String]? {
return habit.completedDates ?? nil
}


I think there is a problem in computeCheckedDates method which I haven't been able to figure out because as soon as I return only the current day's checked/unchecked status, the app runs just fine.

I am using the days property in a ForEach in SwiftUI and as soon I remove this code, the app also runs completely fine. But with the code I have shared days get computed again and again infinitely as soon as the system date changes to the next day.

Any suggestions?


I am using the days property in a ForEach in SwiftUI

Would be helpful to show the code
Hi @Claude31, heres the code for checkbox where days is actually being used:

Code Block
var checkboxes: some View {
    HStack {
      if days.count > 0 {
        ForEach(days.reversed(), id: \.id) {day in
          VStack() {
            Text(day.dayValue)
              .fontWeight(.light)
              .font(.callout)
            if !day.checked && !day.passed {
              Image(systemName: "circle")
                .resizable()
                .frame(width: daysCircleRadius, height: daysCircleRadius)
            } else if !day.checked && day.passed {
              Image(systemName: "multiply.circle")
                .resizable()
                .frame(width: daysCircleRadius, height: daysCircleRadius)
            } else {
                Image(systemName: "checkmark.circle")
                  .resizable()
                  .frame(width: daysCircleRadius, height: daysCircleRadius)
            }
        }
      }
    }
  }

When I comment out the ForEach in here, the app works perfectly, without showing the checkboxes
I think I found a better way of doing this. Rather than keeping days as a computed property, I changed it to @State and moved its computation implementation to the View's top level ZStack's onAppear. It was most certainly being called somewhere in my code again and again. But I only needed to calculate days only once to begin with so there was no point in making it a computed property in the first place.
Computed property gets computed infinitely and SwiftUI becomes unresponsive
 
 
Q