SwiftUI中为何子视图ViewModel属性的onChange监听不生效?
问题原因
ContentViewVM里的@Published var childVM只会在childVM这个实例本身被替换(比如重新赋值一个新的ChildVM对象)时,才会通知ContentView更新视图。但childVM内部的isPaymentPresented属性变化时,ContentViewVM并不会触发任何变更通知,所以ContentView的.onChange监听不到这个深层变化。ChildView里用@StateObject声明传入的viewModel是错误的——@StateObject用于让视图自己创建并持有ViewModel实例,而这里的viewModel是从父视图传过来的,应该用@ObservedObject来观察外部对象的变化。
解决方案
方案1:直接订阅子ViewModel的属性发布者
用.onReceive直接监听childVM.isPaymentPresented的变化,无需经过父ViewModel转发:
class ContentViewVM: ObservableObject { @Published var childVM = ChildVM() } struct ContentView: View { @StateObject var contentVM = ContentViewVM() var body: some View { ChildView(viewModel: contentVM.childVM) .onReceive(contentVM.childVM.$isPaymentPresented) { newValue in print("Change Observed: \(newValue)") } } } struct ChildView: View { @ObservedObject var viewModel: ChildVM var body: some View { Button("Deep Level Trigger") { viewModel.isPaymentPresented.toggle() print("Deep Level Triggered: \(viewModel.isPaymentPresented)") } } } class ChildVM: ObservableObject { @Published var isPaymentPresented: Bool = false }
方案2:在父ViewModel中转发子属性的变化
通过Combine让ContentViewVM监听childVM的属性变化,并同步到自身的@Published属性,这样ContentView就能用原来的.onChange监听:
import Combine class ContentViewVM: ObservableObject { @Published var childVM = ChildVM() @Published var isPaymentPresented = false private var cancellables = Set<AnyCancellable>() init() { childVM.$isPaymentPresented .assign(to: \.isPaymentPresented, on: self) .store(in: &cancellables) } } struct ContentView: View { @StateObject var contentVM = ContentViewVM() var body: some View { ChildView(viewModel: contentVM.childVM) .onChange(of: contentVM.isPaymentPresented) { newValue in print("Change Observed: \(newValue)") } } } struct ChildView: View { @ObservedObject var viewModel: ChildVM var body: some View { Button("Deep Level Trigger") { viewModel.isPaymentPresented.toggle() print("Deep Level Triggered: \(viewModel.isPaymentPresented)") } } } class ChildVM: ObservableObject { @Published var isPaymentPresented: Bool = false }
内容的提问来源于stack exchange,提问作者Aaban Tariq Murtaza
相关产品推荐
相关产品推荐

