Reputation: 129
I am trying to create a calorie counter view using SwiftUI where workout data is fetched from Core Data and besides writing all of the data out I want to get total number of burnt calories for today. I was thinking of going through the fetched data, check whether its createdAt
attribute equals current Date()
and if so add it up to sum of self.totalCaloriesBurntToday
.
I got an error that ForEach of this type does not conform to certain protocols:
Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols
Here is my code:
import SwiftUI
struct ProgressBar: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(
entity: WorkoutInputData.entity(),
sortDescriptors: []
) var workoutData: FetchedResults<WorkoutInputData>
@State private var totalCaloriesBurntToday : Int
var body: some View {
ForEach(workoutData) { singleWorkout in
if singleWorkout.createdAt == Date(){
self.totalCaloriesBurntToday += Int(singleWorkout.caloriesBurnt)!
}
}
return Text("\(self.totalCaloriesBurntToday)")
}
}
I want to output the sum later and want it to change dynamically. Everytime some data object is added or deleted the sum would automatically adjust.
I have tried to go around this using UserDefaults to save the calories there, but there is the problem that the change of data in UserDefaults does not automatically push for changes in the view and hence it is not dynamic.
Upvotes: 2
Views: 337
Reputation: 54436
The SwiftUI's ForEach
you used has a return type of Content
, which means for every item in the loop it has to return some View
. It's not the same as a simple foreach
loop.
You can use reduce
to calculate totalCaloriesBurnt
and filter
to choose only today's workouts.
For comparing dates it's better to use Calendar.compare
:
Calendar.current.compare(singleWorkout.createdAt, to: Date(), toGranularity: .day) == .orderedSame
Summing up your code can look like this:
workoutData
.filter { Calendar.current.compare($0.createdAt, to: Date(), toGranularity: .day) == .orderedSame }
.reduce(0) { $0 + Int($1.caloriesBurnt)! }
Upvotes: 1