Post

Replies

Boosts

Views

Activity

Issues with healthkit's update handlers
I can't seem to wrap my head around with long running queries in HealthKit when it comes dealing with the update handlers. I ask because from my end when I upload my code to the physical device, my data is reloaded and appending to my array which is adding additional data to the screen. From my understanding the updateHandlers monitors for new data/values in the background to update the value in a new view. I'm trying to mimic the Apple Fitness/Health app where the value updates and displays it to the user without having to close the app or switch views. I tried to be concise with my code mainly to get an idea of the updateHandler. I tried stopping the query and .onDisappear modifier but the .onDisappear wouldn't update the values unless I force closed the app and opened it again. //Properties within my view model for resting HR. var restingHRquery: HKStatisticsCollectionQuery? @Published var restingHR: [RestingHeartRate] = [RestingHeartRate]() func calculateRestingHRData() { let restingHRpredicate = HKQuery.predicateForSamples(withStart: oneWeekAgo, end: nil, options: .strictStartDate) restingHRquery = HKStatisticsCollectionQuery(quantityType: restingHeartRateType, quantitySamplePredicate: restingHRpredicate, options: .discreteAverage, anchorDate: anchorDate, intervalComponents: daily) restingHRquery!.initialResultsHandler = { restingQuery, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } restingHRquery!.statisticsUpdateHandler = { restingQuery, statistics, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } guard let restingHRquery = self.restingHRquery else { return } self.healthStore?.execute(restingHRquery) } My chart always being updated which causes it to reload my list and draw new data on the charts which makes the line go crazy. I'm using the EnvironmentObject because it's a subview. I'm just getting straight to the chart view struct OneWeekRestHRChartView: View { @EnvironmentObject var healthStoreVM: HealthStoreViewModel var body: some View { VStack(alignment: .leading, spacing: 10) { Text("Average: \(healthStoreVM.averageRestHR) bpm") .font(.headline) Chart { ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHrData in LineMark(x: .value("day", restHrData.date, unit: .day), y: .value("RHR", restHrData.restingValue) ) .interpolationMethod(.catmullRom) .foregroundStyle(.red) .symbol() { Circle() .fill(.red) .frame(width: 15) } } } .frame(height: 200) .chartYScale(domain: 30...80) .chartXAxis { AxisMarks(values: .stride(by: .day)) { AxisGridLine() AxisValueLabel(format: .dateTime.day().month(), centered: true) } } } .padding(.horizontal) .navigationTitle("Resting Heart Rate") List{ ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHR in DataListView(imageText: "heart.fill", imageColor: .red, valueText: "\(restHR.restingValue) bpm", date: restHR.date) } } .listStyle(.inset) } } Could this just be a SwiftUI chart issue?
0
0
660
Apr ’23
How can I read and display workout data similar to Apple Fitness?
I'm looking to display the workouts performed similar to what Apple Fitness displays. However, I want to get traditional strength training and functional strength training workouts particularly. I would also like to get the number of workouts performed within the week. I'm having issues reading the data and displaying it. Below is the code I'm using. I'm omitting the authorization method because I have that with other health variables I'm getting. Also, when I try to get the workoutActivity type to display, nothing is showing up. I've looked over apple's healthkit documentation but getting a big confused/lost as a beginner, particularly with the workout data. I've attached pictures as a reference on what I would like to accomplish var selectedWorkoutQuery: HKQuery? @Published var muscleStrength: [HKWorkout] = [HKWorkout]() func getStrengthTrainingWorkouts() { let date = Date() let startDate = Calendar.current.dateInterval(of: .weekOfYear, for: date)?.start let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictStartDate) let traditionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining) let functionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .functionalStrengthTraining) let strengthCompound = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, traditionalStrengthTrainingPredicate, functionalStrengthTrainingPredicate]) let selectedWorkoutQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: strengthCompound, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { strengthQuery, samples, error in guard let samples = samples else { fatalError("An error has occured \(error?.localizedDescription)") } DispatchQueue.main.async { if let workouts = samples as? [HKWorkout] { for workout in workouts { self.muscleStrength.append(workout) } } } } self.healthStore?.execute(selectedWorkoutQuery) } Here is the view I would like to display the count and workouts but nothing is showing struct MuscleView: View { @ObservedObject var healthStoreVM: HealthStoreViewModel var body: some View { List(healthStoreVM.muscleStrength, id: \.self) { workout in Text("\(workout.workoutActivityType.rawValue)") } } }
1
0
1.1k
Feb ’23
Can't display Workout count using HealthKit in SwiftUI
I'm trying to get the number of workouts performed within the week and want to display it in a view. Is there a way to get the count? I tried to access the count value by the .count property on the array that stores the workouts. Below is the code I'm using. I'm omitting the authorization method because I have that with other health variables I'm getting. Any help would be appreciated class HealthStoreViewModel: ObservableObject { var selectedWorkoutQuery: HKQuery?   @Published var muscleStrength: [HKWorkoutActivityType] = [HKWorkoutActivityType]() func getStrengthTrainingWorkouts() { let date = Date() let startDate = Calendar.current.dateInterval(of: .weekOfYear, for: date)?.start let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictStartDate) let traditionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining) let functionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .functionalStrengthTraining) let strengthCompound = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, traditionalStrengthTrainingPredicate, functionalStrengthTrainingPredicate]) let selectedWorkoutQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: strengthCompound, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { strengthQuery, samples, error in DispatchQueue.main.async { guard let workouts = samples as? HKWorkout else { return } self.muscleStrength.append(workouts.workoutActivityType) } } guard let selectedWorkoutQuery = self.selectedWorkoutQuery else { return } self.healthStore?.execute(selectedWorkoutQuery) }
1
0
1.1k
Feb ’23