My question is the following:
Can I change the
HKWorkoutConfiguration.activityType
during aHKWorkoutSession
or does eachHKWorkoutSession
has to have its ownHKWorkoutConfiguration.activityType
?
I want to create a workout app where you can create a workout consisting of different sets with different activity types. For example a Shadowing Boxing Workout, consisting of 3 sets of Boxing and 3 sets of Kickboxing (Boxing and Kickboxing are the different activities).
Ideally I would just start the HKWorkoutSession
once at the beginning and end it after all sets for each activity are done, changing the HKWorkoutConfiguration.activityType
in-between.
My current approach is based on the sample provided by Apple: https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/speedysloth_creating_a_workout
I adjusted the startWorkout()
method to startWorkout(for type: String)
. It now looks like this:
// Start the workout.
func startWorkout(for type: String) {
// Start the timer.
setUpTimer()
self.running = true
// Create the session and obtain the workout builder.
/// - Tag: CreateWorkout
do {
session = try HKWorkoutSession(healthStore: healthStore, configuration: self.workoutConfiguration(for: type))
builder = session.associatedWorkoutBuilder()
} catch {
// Handle any exceptions.
return
}
// Setup session and builder.
session.delegate = self
builder.delegate = self
// Set the workout builder's data source.
/// - Tag: SetDataSource
builder.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
workoutConfiguration: workoutConfiguration(for: type))
// Start the workout session and begin data collection.
/// - Tag: StartSession
session.startActivity(with: Date())
builder.beginCollection(withStart: Date()) { (success, error) in
// The workout has started.
}
print("New Workout has started")
}
In the method I get the respective activity by workoutConfiguration(for: type)
which looks up the right activity from a string.
After a set is done (e.g. the boxing set), I end the session and start a new workout and session for the new set with the new activity.
My problem with the current approach is that I need to end the current HKWorkoutSession
before I start the new one. But ending the session the way its done in the example does not execute immediately and therefore the new set of the workouts starts without saving the old set to the HKStore with the right activity.
Therefore I thought I would be nice to start the session just once and switch activityTypes in-between. However, I don't know if it is possible (maybe complications with HKStore) and how it is done.
Or is there any other smart way of doing things to achieve this?
I'm just starting out with iOS Programming.
Any help is greatly appreciated!
Disclaimer: This isn't a full answer, but an approach I'd take to address the problem.
Look at the workoutSession(_:didChangeTo:from:date:)
method. Documentation Link
When one type of workout ends that method will receive a notification. As long as you haven't called session.end()
the workout session should still be active. Use your healthStore
instance to save the previous workout session before starting a new one.
It could look like this;
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
if toState == .ended {
workoutBuilder.endCollection(withEnd: date) { (success, error) in
// collection has ended for one type of workout
self.workoutBuilder.finishWorkout { (workout, error) in
// unwrap the optional `workout`
guard let completedWorkout = workout else { return }
// save workout to health store
healthStore.save(completedWorkout) { (success, error) in
if success {
// begin a new workout by calling your method to start a new workout with a new configuration here
startWorkout(for type: String)
}
}
}
}
}
}
That is likely going to cause issues with your Timer since you're calling setUpTimer
again but you can work with that. Also this doesn't address the point when the user is completely done with their workout and doesn't want to start a new workout type.