For some reason after the first time I tap the Indulge button the UI stops updating. The indulgences array count stops incrementing and the computed property pctIntervalComplete stops updating.
struct Habit: Hashable {
static func == (lhs: Habit, rhs: Habit) -> Bool {
return lhs.habitId == rhs.habitId
}
public let habitId: UUID
public var habitName: String
public var indulgences: [Indulgence]
public var daysInterval: Int
public var hoursInterval: Int
public var minsInterval: Int
public var secsInterval: Int
public var daysIncrease: Int
public var hoursIncrease: Int
public var minsIncrease: Int
public var secsIncrease: Int
private let minutesToSeconds: Int = 60
private let hoursToSeconds: Int = 3600
private let daysToSeconds: Int = 86400
public var pctIntervalComplete: Double {
guard let latestIndulgence = indulgences.last else {
return 0.0
}
let currentInterval = Date.now.timeIntervalSinceReferenceDate - latestIndulgence.timestamp.timeIntervalSinceReferenceDate
return currentInterval / targetIntervalInSeconds
}
public var isIntervalComplete: Bool {
return pctIntervalComplete >= 1.0
}
private var targetIntervalInSeconds: TimeInterval {
return TimeInterval((daysInterval * daysToSeconds) + (hoursInterval * hoursToSeconds) + (minsInterval * minutesToSeconds) + secsInterval)
}
init(habitId: UUID = UUID(), habitName: String) {
self.habitId = habitId
self.habitName = habitName
indulgences = [Indulgence]()
daysInterval = 0
hoursInterval = 0
minsInterval = 1
secsInterval = 0
daysIncrease = 0
hoursIncrease = 0
minsIncrease = 1
secsIncrease = 0
}
mutating public func addIndulgence() {
var i = Indulgence(habitId: self.habitId)
indulgences.append(i)
}
}
struct Indulgence: Hashable {
public let indulgenceId: UUID
public let habitId: UUID
public let timestamp: Date
init(indulgenceId: UUID = UUID(), habitId: UUID, timestamp: Date = Date.now) {
self.indulgenceId = indulgenceId
self.habitId = habitId
self.timestamp = timestamp
}
}
struct HabitListView: View {
@State private var habitList = [Habit(habitName: "Habit 1"), Habit(habitName: "Habit 2")]
var body: some View {
List {
ForEach($habitList, id: \.habitId) { $habit in
HStack{
Text(habit.habitName)
Spacer()
Button("Indulge") {
habit.addIndulgence() //only works once
}.buttonStyle(.borderedProminent)
.tint(habit.isIntervalComplete ? .pink : .gray)
TimelineView(.periodic(from: Date.now, by: 1)) { _ in
CircularProgressView(progress: habit.pctIntervalComplete) //stops updating
.frame(maxHeight: 36)
.scaleEffect(0.35)
Text("\(habit.indulgences.count)") //stops incrementing
}
}
}
}
}
}
struct CircularProgressView: View {
let progress: Double
let lineWidth: CGFloat = 7
var body: some View {
ZStack {
Circle()
.stroke(
Color.pink.opacity(0.5),
lineWidth: lineWidth
)
Circle()
.trim(from: 0, to: progress)
.stroke(
Color.pink,
style: StrokeStyle(
lineWidth: lineWidth,
lineCap: .round
)
)
.rotationEffect(.degrees(-90))
.animation(.easeOut, value: progress)
}
}
}
>Solution :
You are lying to the compiler by providing your own Equatable conformance:
static func == (lhs: Habit, rhs: Habit) -> Bool {
return lhs.habitId == rhs.habitId
}
By doing this, you’re telling it that any Habit that has the same habitId is completely equal. This is not true — they are not equal if they have different properties (such as number of indulgences).
Remove this and it will work.