Using Combine's Publishers and Subscribers to publish real time HealthKit data?

Viewed 281

I've always used delegation in UIKit and WatchKit to communicate between objects as far as passing around data from e.g. a WorkoutManager ViewModel that receives delegate callbacks from HealthKit during an HKworkout for calories, heart rates, to an InterfaceController.

I'm now trying to use Combine and SwiftUI to pass around the same data and am a little lost. I'm using a WorkoutManager class as an environment object that I initialize in my ContentView:

class WorkoutManager: NSObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate, ObservableObject  {

    @Published var totalEnergyBurned: Double = 0

    //How to subscribe to the changes? 

//Omitted HealthKit code that queries and pushes data into totalEnergyBurned here

}



struct ContentView: View {
    
    let healthStore = HKHealthStore()
    @StateObject var workoutManager = WorkoutManager()
    
    var sessionTypes = [SessionType.Game, SessionType.Practice, SessionType.Pickup]
    
    var body: some View {
        
        List {
            ForEach(sessionTypes) { sessionType  in
                NavigationLink(destination: LiveWorkoutView(sessionType: sessionType)) {
                    SessionTypeRow(name: sessionType.stringValue)
                }
            }
        }
        .navigationTitle("Let's Go!")
        .onAppear {
            let authorizationStatus = healthStore.authorizationStatus(for: HKSampleType.workoutType())
            switch authorizationStatus {
            case .sharingAuthorized:
                print("sharing authorized")
            case .notDetermined:
                print("not determined")
                HealthKitAuthManager.authorizeHealthKit()
            case .sharingDenied:
                print("sharing denied")
                HealthKitAuthManager.authorizeHealthKit()
            default:
                print("default in healthStore.authorizationStatus in ContentView")
                HealthKitAuthManager.authorizeHealthKit()
            }
        }
    }
}

My goal is to Publish the changes to all of the children of ContentView but I'm not sure how to subscribe to the changes?

import SwiftUI

struct LiveWorkoutView: View {

@State var sessionType: SessionType
    
    @StateObject var workoutManager = WorkoutManager()
    
    var body: some View {
        VStack {
            Text("\(workoutManager.totalEnergyBurned)")
            Button(action: {
                workoutManager.stopWorkout()
            }) {
                Text("End Workout")
            }
        }
        .onAppear {
            workoutManager.startWorkout()
            workoutManager.sessionType = sessionType
        }
        .navigationTitle(sessionType.stringValue)
    }
}
1 Answers

//How to subscribe to the changes?

You don't. @StateObject injects subscriber in view, so just use workoutManager. totalEnergyBurned property somewhere (where needed) in view body and view will be refreshed automatically once this property changed (eg. you assign new value to it from HealthKit callback.

Related