When I go to mutate the "rings" property of the main() object created in the "content view", it does not change. The makeQuery() function doesn't change the rings property of "fitness" created in content view. Why is makeQuery() not changing this property of the fitness object? I have tried pretty much every brute force technique I could think of.
import SwiftUI
import HealthKit
struct ContentView: View {
var body: some View {
Text("hello!").padding().onAppear {
var fitness = main()
fitness.main()
print(fitness.rings)
//this is always null even though the makeQuery function which should mutate the rings value does nothing when called here.
}
}
}
struct fitnessView: View {
@State var rings : HKActivitySummary
var body: some View {
let red = Int(rings.activeEnergyBurned.doubleValue(for: .largeCalorie()))
let green = Int(rings.appleExerciseTime.doubleValue(for: .minute()))
//let blue = Int(rings.appleStandHours.doubleValue(for: .hour()))
VStack {
Text("\(red)").foregroundColor(.red)
Text("\(green)").foregroundColor(.green)
//Text("\(blue)").foregroundColor(.blue)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
class main {
let healthstore = HKHealthStore()
var rings : HKActivitySummary = HKActivitySummary()
func authorizeHealthkit() {
let allTypes = Set([HKObjectType.activitySummaryType()])
healthstore.requestAuthorization(toShare: nil, read: allTypes) { (chk, error) in if(chk) {
print("permission granted")
}
}
}
func makeQuery() {
let calendar = NSCalendar.current
let endDate = Date()
guard let startDate = calendar.date(byAdding: .day, value: 0, to: endDate) else {
fatalError("error")
}
let units: Set<Calendar.Component> = [.day, .month, .year, .era]
var startDatecomps = calendar.dateComponents(units, from: startDate)
startDatecomps.calendar = calendar
var endDatecomps = calendar.dateComponents(units, from: endDate)
endDatecomps.calendar = calendar
let summariesWithinRange = HKQuery.predicate(forActivitySummariesBetweenStart: startDatecomps, end: endDatecomps)
let query = HKActivitySummaryQuery(predicate: summariesWithinRange) {
(sample, results, error) -> Void in
if let results = results {
if let summary = results.first {
self.rings = summary
// self.rings successfully mutated here when I print it out
// but does not result in the actual "fitness" object changing
}
}
}
healthstore.execute(query)
}
func getRings() -> HKActivitySummary {
return self.rings
}
func main() {
self.authorizeHealthkit()
self.makeQuery()
print(self.getRings())
}
}
Thanks for the help
CodePudding user response:
In your ContentView
, try modify your code as below:
struct ContentView: View {
@StateObject var fitness = main() //this part
var body: some View {
Text("hello!").padding().onAppear {
fitness.main() //this part
print(fitness.rings)
//this is always null even though the makeQuery function which should mutate the rings value does nothing when called here.
}
}
}
And in your class main
modify these parts:
class main : ObservableObject { //this part
let healthstore = HKHealthStore()
@Published var rings : HKActivitySummary = HKActivitySummary() //this part
CodePudding user response:
HKActivitySummary is a class, so you cannot use @State. Also, you cannot use @StateObject wrapper, because it does not conform to ObservableObject. You have to wrap HKActivitySummary in some envelope, and program a mechanism that will check for changes. More work to do, or choose another approach.
Class names should start with capital, so rename main to Main. main and Main are not good choices for names, as these are used by Swift, rename these.