Receiving Downhill Skiing and Snowboarding Data
Receive segments and distance samples during downhill skiing and snowboarding workout sessions.
Overview
On Apple Watch Series 3, the system automatically generates distance samples, segments, and pause and resume events during HKWorkoutActivityType.downhillSkiing and HKWorkoutActivityType.snowboarding workout sessions. Monitor these samples to receive additional information about individual runs. You can then display this information on the watch during the session.
Receiving Distance Samples
The system generates a distanceDownhillSnowSports sample at the end of each run. Use an HKAnchoredObjectQuery query to receive and process these samples.
let updateHandler: ((HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) = { [unowned self] (query, samplesOrNil, deletedObjectsOrNil, newAnchorOrNil, errorOrNil) in
// Check for errors.
if let error = errorOrNil {
// Handle the error here.
print("*** An error occurred: \(error.localizedDescription) ***")
return
}
// Process the samples.
if let samples = samplesOrNil {
// Do something with the distance samples here.
print("Samples: \(samples)")
}
// Update the anchor.
if let newAnchor = newAnchorOrNil {
self.myCurrentAnchor = newAnchor
}
}
// Get the downhill skiing type.
guard let downhillSnowSport = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceDownhillSnowSports) else {
fatalError("*** Unable to get the downhill snow sport type ***")
}
// Only find samples that start after the workout began.
let datePredicate = NSPredicate(format: "%K > %@", HKPredicateKeyPathStartDate, workoutStartDate as NSDate)
let distanceQuery = HKAnchoredObjectQuery(type: downhillSnowSport,
predicate: datePredicate,
anchor: myCurrentAnchor,
limit: HKObjectQueryNoLimit,
resultsHandler: updateHandler)
distanceQuery.updateHandler = updateHandler
// Run the query.
store.execute(distanceQuery)Receiving Segments
The system generates a segment event for each run. This event is passed to your app using the session delegate’s workoutSession(_:didGenerate:) method.
func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
// Check to see if the event is a segment.
if event.type == .segment {
// Get the segment's start and end times.
let startTime = event.dateInterval.start
let endTime = event.dateInterval.end
// Get the segment's metadata.
let averageSpeed = event.metadata?[HKMetadataKeyAverageSpeed]
let maxSpeed = event.metadata?[HKMetadataKeyMaximumSpeed]
let alpineSlope = event.metadata?[HKMetadataKeyAlpineSlopeGrade]
let elevationDescended = event.metadata?[HKMetadataKeyElevationDescended]
// Do something with the segment data here...
}
// Also handle any other event types...
}
Each autogenerated segment has a metadata dictionary with the following keys and values:
Handling Pause and Resume Events
The system automatically generates HKWorkoutEventType.motionPaused and HKWorkoutEventType.motionResumed events for HKWorkoutActivityType.downhillSkiing and HKWorkoutActivityType.snowboarding sessions:
HKWorkoutEventType.motionPaused events are generated at the end of each run.
HKWorkoutEventType.motionResumed events are generated at the beginning of the next run.
These events are similar to the motion events generated for HKWorkoutActivityType.running workout sessions; however, unlike HKWorkoutActivityType.running sessions, HKWorkoutActivityType.downhillSkiing and HKWorkoutActivityType.snowboarding sessions do not continue to run in the background while paused. As a result, you should use these events to pause and resume any other long-running tasks your app is performing (for example, location tracking).