Reputation: 6690
My understanding is a CurrentValueSubject publisher in Combine is good for accessing on demand, as opposed to a regular Publisher that emits a value once. So I'm trying to use one here in an Environment Object to store the total energy burned in an HKWorkout so that I can access it after the workout is finished in a SwiftUI View. With the code below I get the compiler error Cannot convert return expression of type 'AnyCancellable' to return type 'Double'
so I think I need to do some type of casting but can't figure it out?
class WorkoutManager: NSObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate, ObservableObject {
var finishedWorkoutTotalEnergyBurned = CurrentValueSubject<Double, Never>(0.0)
func stopWorkout() {
self.finishedWorkoutTotalEnergyBurned.value = unwrappedWorkout.totalEnergyBurned!.doubleValue(for: .kilocalorie())
}
}
struct SummaryView: View {
@StateObject var workoutManager = WorkoutManager()
var body: some View {
Text("\(getFinishedWorkoutTotalEnergyBurned())")
.navigationBarHidden(true)
//.navigationTitle("Workout Complete")
}
func getFinishedWorkoutTotalEnergyBurned() -> Double {
workoutManager.finishedWorkoutTotalEnergyBurned.sink(receiveValue: { $0 })
}
}
Upvotes: 5
Views: 4261
Reputation: 49590
I think your question shows that you need to learn a bit more the foundational principle behind SwiftUI, and behind Combine (that statement about "CurrentValueSubject vs regular Publisher" was quite wrong).
All you need here is to expose a @Published
property on your WorkoutManager
, and set it to the value that you want, when needed:
class WorkoutManager: NSObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate, ObservableObject {
@Published var finishedWorkoutTotalEnergyBurned = 0.0
func stopWorkout() {
finishedWorkoutTotalEnergyBurned = unwrappedWorkout.totalEnergyBurned!.doubleValue(for: .kilocalorie())
}
}
struct SummaryView: View {
@StateObject var workoutManager = WorkoutManager()
var body: some View {
Text("\(workoutManager.finishedWorkoutTotalEnergyBurned)")
.navigationBarHidden(true)
}
}
@Published
does use a Combine publisher under the hood, which in combination with @StateObject
cause the view to update. But all you need to reason about here, is how and when to set these properties - and the view will update automatically. In the case you showed, there's likely no need to use a publisher directly.
Upvotes: 1