🩺

【iOS】Workoutの詳細データを管理する

2024/06/13に公開

HealthKitを使用してWorkoutサンプルを作成する際、継続時間、移動距離、およびエネルギー消費量などの情報が含まれます。これらのWorkoutをさらに詳細にするためには、追加の詳細サンプルを作成し、それらをWorkoutに関連付けることができます。

https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/adding_samples_to_a_workout

サンプルをWorkoutに関連付けるには、HealthKitStoreのadd(_:to:completion:)メソッドを使用します。Workoutはサンプルを追加する前に、HealthKitStoreへ保存されている必要があります。

Workoutデータの収集

サンプルをWorkoutに関連付けることで、Workoutの詳細な情報を提供できます。例えば、ランニングを追跡するアプリはランニング終了後に総距離、継続時間、および消費カロリーを含むWorkoutを作成します。さらに、距離、消費カロリー、ステップ数、心拍数、登った階数などのデータを短いインターバルで保存できます。

Workoutサンプルの作成と保存

まず、消費エネルギーと総移動距離のHKQuantityを作成します。

let energyBurned = HKQuantity(unit: HKUnit.largeCalorie(), doubleValue: 425.0)
let distance = HKQuantity(unit: HKUnit.mile(), doubleValue: 3.2)

次に、Workoutサンプルを作成します。

let run = HKWorkout(activityType: .running,
                    start: start,
                    end: end,
                    duration: 0,
                    totalEnergyBurned: energyBurned,
                    totalDistance: distance,
                    metadata: nil)

そして、WorkoutサンプルをHealthKitStoreに保存します。

store.save(run) { (success, error) -> Void in
    guard success else {
        // 適切なエラーハンドリングを行います。
        return
    }
    
    // 詳細サンプルをここに追加します。
}

詳細サンプルの追加

完了ハンドラ内で保存が成功したことを確認し、Workoutに詳細サンプルを追加します。例えば、Workoutを一定のインターバルに分割し、各インターバルの詳細情報を計算します。以下のコードは、最初のインターバルでサンプルを作成します。

移動距離

guard let distanceType = HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning) else {
    fatalError("*** 距離タイプを作成できません ***")
}

let distancePerInterval = HKQuantity(unit: HKUnit.foot(), doubleValue: 165.0)

let distancePerIntervalSample = HKQuantitySample(type: distanceType,
                                                 quantity: distancePerInterval,
                                                 start: myIntervals[0],
                                                 end: myIntervals[1])

myDetailSamples.append(distancePerIntervalSample)

消費エネルギー

guard let energyBurnedType = HKObjectType.quantityType(forIdentifier: .activeEnergyBurned) else {
    fatalError("*** エネルギー消費タイプを作成できません ***")
}

let energyBurnedPerInterval = HKQuantity(unit: HKUnit.largeCalorie(), doubleValue: 15.5)

let energyBurnedPerIntervalSample = HKQuantitySample(type: energyBurnedType,
                                                     quantity: energyBurnedPerInterval,
                                                     start: myIntervals[0],
                                                     end: myIntervals[1])

myDetailSamples.append(energyBurnedPerIntervalSample)

心拍数

guard let heartRateType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
    fatalError("*** 心拍数タイプを作成できません ***")
}

let heartRateForInterval = HKQuantity(unit: HKUnit(from: "count/min"), doubleValue: 95.0)

let heartRateForIntervalSample = HKQuantitySample(type: heartRateType,
                                                  quantity: heartRateForInterval,
                                                  start: myIntervals[0],
                                                  end: myIntervals[1])

myDetailSamples.append(heartRateForIntervalSample)

インターバルのすべてのサンプルを作成します。その後、HealthKitStoreを使用してこれらのサンプルをWorkoutに追加します。

store.add(myDetailSamples, to: run) { (success, error) -> Void in
    guard success else {
        // 適切なエラーハンドリングを行います。
        return
    }
}

関連サンプルの読み取り

Workoutの詳細情報を読み取るには、Workoutに関連するサンプルのみを返すクエリを作成する必要があります。predicateForObjects(from:)メソッドを使用して、Workoutに関連するサンプルのみを一致させる条件を作成します。その条件を使用して、クエリをフィルタリングできます。例えば、次のコードはWorkoutに関連するすべての距離サンプルを返します。

guard let distanceType = HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning) else {
    fatalError("*** 距離タイプを作成できません ***")
}

let workoutPredicate = HKQuery.predicateForObjects(from: workout)

let startDateSort = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true)

let query = HKSampleQuery(sampleType: distanceType,
                          predicate: workoutPredicate,
                          limit: 0,
                          sortDescriptors: [startDateSort]) { (sampleQuery, results, error) -> Void in
                            guard let distanceSamples = results as? [HKQuantitySample] else {
                                // 適切なエラーハンドリングを行います。
                                return
                            }
                            
                            // Workoutの距離サンプルをここで使用します。
}

store.execute(query)

Workoutに関連するすべてのデータタイプについて、個別のクエリ(HKSampleQuery)を作成する必要があります。例えば、前述のWorkoutの詳細を取得するには、距離、消費エネルギー、および心拍数のそれぞれについて個別のクエリが必要です。

以上が、HealthKitを使用してWorkoutサンプルを作成し、詳細データを関連付ける方法です。

最後に

間違い・気になる部分がありましたら、コメントいただけると大変うれしいです。
良かったと思ったら記事へのいいねXのフォローをよろしくお願いいたします。

https://sites.google.com/view/muranakar

個人でアプリを作成しています。良かったら覗いてみてください。

Discussion