为何SwiftUI中使用@StateObject绑定值时ChildView未更新?
1. @StateObject 与 @ObservedObject 的核心差异
@StateObject 是 SwiftUI 用来管理跨视图生命周期持久化的ObservableObject实例的属性包装器:一旦ChildView首次初始化,@StateObject修饰的viewModel就会被SwiftUI保留下来,后续即便父视图(ContentView)的状态变化导致ChildView的body重新计算,这个viewModel实例也不会被重新创建。
而@ObservedObject的实例生命周期完全由开发者控制——每次ContentView的amount变化触发ChildView的body重算时,你的代码会在init里重新生成一个MyViewModel实例,新实例持有最新的Binding值,所以ChildView的Text能显示更新后的数据。但这是错误用法,会导致ViewModel频繁销毁重建,违背了ObservableObject的设计初衷。
2. 代码核心问题
MyViewModel虽然持有Binding
方案一:让ViewModel监听Binding变化并发送通知
修改MyViewModel,用@Published属性同步Binding的值,同时监听Binding变化来更新自身状态:
class MyViewModel: ObservableObject { @Published var localAmount: Int private var cancellables = Set<AnyCancellable>() init(amount: Binding<Int>) { self.localAmount = amount.wrappedValue // 监听Binding变化,同步到localAmount amount.projectedValue .assign(to: \.localAmount, on: self) .store(in: &cancellables) // localAmount变化时,同步回原Binding $localAmount .sink { newValue in amount.wrappedValue = newValue } .store(in: &cancellables) } } // 对应的ChildView修改: struct ChildView: View { @StateObject var viewModel: MyViewModel init(amount: Binding<Int>) { self._viewModel = StateObject(wrappedValue: MyViewModel(amount: amount)) } var body: some View { VStack { TextField("", value: $viewModel.localAmount, format: .number) .multilineTextAlignment(.center) Text("ChildView amount: \(viewModel.localAmount)") // 现在会正常更新 } } }
方案二:直接使用@Binding(简单场景首选)
如果ViewModel逻辑不复杂,可以跳过ViewModel,直接在ChildView中使用@Binding:
struct ChildView: View { @Binding var amount: Int var body: some View { VStack { TextField("", value: $amount, format: .number) .multilineTextAlignment(.center) Text("ChildView amount: \(amount)") } } }
内容的提问来源于stack exchange,提问作者Markus Rollmann

