如何使用 Combine 的 CurrentValueSubject 并在 SwiftUI 视图中访问它?
How to use Combine's CurrentValueSubject and access it in a SwiftUI View?
我的理解是 Combine 中的 CurrentValueSubject 发布者适合按需访问,而不是发出一次值的常规发布者。因此,我尝试在环境对象中使用一个来存储 HKWorkout 中燃烧的总能量,以便我可以在 SwiftUI 视图中完成锻炼后访问它。使用下面的代码我得到编译器错误 Cannot convert return expression of type 'AnyCancellable' to return type 'Double'
所以我想我需要做一些类型的转换但无法弄清楚?
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: { [=10=] })
}
}
我认为你的问题表明你需要更多地了解 SwiftUI 和 Combine 背后的基本原则(关于“CurrentValueSubject vs regular Publisher”的说法是完全错误的)。
您在这里所需要做的就是在您的 WorkoutManager
上公开一个 @Published
属性,并在需要时将其设置为您想要的值:
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
确实在幕后使用了 Combine 发布者,它与 @StateObject
结合导致视图更新。但是您在这里需要考虑的是如何以及何时设置这些属性 - 视图将自动更新。在您展示的情况下,可能不需要直接使用发布者。
我的理解是 Combine 中的 CurrentValueSubject 发布者适合按需访问,而不是发出一次值的常规发布者。因此,我尝试在环境对象中使用一个来存储 HKWorkout 中燃烧的总能量,以便我可以在 SwiftUI 视图中完成锻炼后访问它。使用下面的代码我得到编译器错误 Cannot convert return expression of type 'AnyCancellable' to return type 'Double'
所以我想我需要做一些类型的转换但无法弄清楚?
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: { [=10=] })
}
}
我认为你的问题表明你需要更多地了解 SwiftUI 和 Combine 背后的基本原则(关于“CurrentValueSubject vs regular Publisher”的说法是完全错误的)。
您在这里所需要做的就是在您的 WorkoutManager
上公开一个 @Published
属性,并在需要时将其设置为您想要的值:
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
确实在幕后使用了 Combine 发布者,它与 @StateObject
结合导致视图更新。但是您在这里需要考虑的是如何以及何时设置这些属性 - 视图将自动更新。在您展示的情况下,可能不需要直接使用发布者。