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)
}
}