[英]SwiftUI - changes in nested View Model classes not detected using onChange method
I have a nested View Model class WatchDayProgramViewModel
as an ObservableObject.我有一个嵌套视图 Model class
WatchDayProgramViewModel
作为 ObservableObject。 Within WatchDayProgramViewModel
, there is a WorkoutModel
that is a child class. I want to detect any updates in the currentHeartRate
to trigger data transfer to iPhone.在
WatchDayProgramViewModel
中,有一个WorkoutModel
是一个孩子 class。我想检测currentHeartRate
中的任何更新以触发数据传输到 iPhone。
Hence, I tried from ContentView using WatchDayProgramViewModel
as an EnvironmentObject
and detecting changes in WorkoutModel
via onChange()
method.因此,我尝试从 ContentView 使用
WatchDayProgramViewModel
作为EnvironmentObject
并通过onChange()
方法检测WorkoutModel
中的变化。 But it seems that SwiftUI views does not detect any property changes in WorkoutModel
.但似乎 SwiftUI 视图没有检测到
WorkoutModel
中的任何属性更改。
I understand that this issue could be due to ObservableObject not detecting changes in child/nested level of classes, and SO answer ( SwiftUI change on multilevel children Published object change ) suggests using struct
instead of class. But changing WorkoutModel
to struct
result in various @Published
properties and functions to show error.我知道这个问题可能是由于 ObservableObject 没有检测到子类/嵌套级别的变化,所以答案( SwiftUI 多级子级的变化发布 object 变化)建议使用
struct
而不是 class。但是将WorkoutModel
更改为struct
导致各种@Published
已@Published
的属性和函数以显示错误。
Is there any possible way to detect changes in child View Model from the ContentView
itself?是否有任何可能的方法从
ContentView
本身检测子视图 Model 的变化?
ContentView内容视图
struct ContentView: View {
@State var selectedTab = 0
@StateObject var watchDayProgramVM = WatchDayProgramViewModel()
var body: some View {
NavigationView {
TabView(selection: $selectedTab) {
WatchControlView().id(0)
NowPlayingView().id(1)
}
.environmentObject(watchDayProgramVM)
.onChange(of: self.watchDayProgramVM.workoutModel.currentHeartRate) { newValue in
print("WatchConnectivity heart rate from contentView \(newValue)")
}
}
}
WatchDayProgramViewModel WatchDayProgramViewModel
class WatchDayProgramViewModel: ObservableObject {
@Published var workoutModel = WorkoutModel()
init() {
}
}
WorkoutModel锻炼模式
import Foundation
import HealthKit
class WorkoutModel: NSObject, ObservableObject {
let healthStore = HKHealthStore()
var session: HKWorkoutSession?
var builder: HKLiveWorkoutBuilder?
@Published var currentHeartRate: Double = 0
@Published var workout: HKWorkout?
//Other functions to start/run workout hidden
func updateForStatistics(_ statistics: HKStatistics?) {
guard let statistics = statistics else {
return
}
DispatchQueue.main.async {
switch statistics.quantityType {
case HKQuantityType.quantityType(forIdentifier: .heartRate):
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
self.currentHeartRate = statistics.mostRecentQuantity()?.doubleValue(for: heartRateUnit) ?? 0
default:
return
}
}//end of dispatchqueue
}// end of function
}
extension WorkoutModel: HKLiveWorkoutBuilderDelegate {
func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) {
for type in collectedTypes {
guard let quantityType = type as? HKQuantityType else {
return
}
let statistics = workoutBuilder.statistics(for: quantityType)
updateForStatistics(statistics)
}
}
}
Try to change尝试改变
@StateObject var watchDayProgramVM = WatchDayProgramViewModel()
with和
@ObservedObject var watchDayProgramVM = WatchDayProgramViewModel()
Figure it out.想办法。 Just had to create another
AnyCancellable
variable to call objectWillChange
publisher.只需创建另一个
AnyCancellable
变量来调用objectWillChange
发布者。
WatchDayProgramViewModel WatchDayProgramViewModel
class WatchDayProgramViewModel: ObservableObject {
@Published var workoutModel = WorkoutModel()
var cancellable: AnyCancellable?
init() {
cancellable = workoutModel.objectWillChange
.sink { _ in
self.objectWillChange.send()
}
}
}
While I have provided my answer, that worksaround with viewmodels, I would love to see/get advice on other alternatives.虽然我已经提供了我的答案,但我很乐意看到/获得有关其他替代方案的建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.