简体   繁体   English

SwiftUI - 使用 onChange 方法未检测到嵌套视图 Model 类中的更改

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM