【发布时间】:2023-03-20 21:39:01
【问题描述】:
我有一个父视图和一个子视图,每个视图都有自己的视图模型。父视图注入子视图的viewModel。
父视图没有正确响应子计算属性isFormInvalid 上的更改(子视图会)。
@Published 不能添加到计算属性中,我在该区域看到的其他问题/答案并没有像这个问题那样专注于拥有单独的视图模型。我想要单独的 viewModel 来增加可测试性,因为子视图可能会变得非常复杂。
这里有一个文件可以最小化重现问题:
import SwiftUI
extension ParentView {
final class ViewModel: ObservableObject {
@ObservedObject var childViewViewModel: ChildView.ViewModel
init(childViewViewModel: ChildView.ViewModel = ChildView.ViewModel()) {
self.childViewViewModel = childViewViewModel
}
}
}
struct ParentView: View {
@ObservedObject private var viewModel: ViewModel
init(viewModel: ViewModel = ViewModel()) {
self.viewModel = viewModel
}
var body: some View {
ChildView(viewModel: viewModel.childViewViewModel)
.navigationBarTitle("Form", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
addButton
}
}
}
private var addButton: some View {
Button {
print("======")
print(viewModel.childViewViewModel.$name)
} label: {
Text("ParentIsValid?")
}
.disabled(viewModel.childViewViewModel.isFormInvalid) // FIXME: doesn't work, but the actual fields work in terms of two way updating
}
}
struct ParentView_Previews: PreviewProvider {
static var previews: some View {
let childVm = ChildView.ViewModel()
let vm = ParentView.ViewModel(childViewViewModel: childVm)
NavigationView {
ParentView(viewModel: vm)
}
}
}
// MARK: child view
extension ChildView {
final class ViewModel: ObservableObject {
// MARK: - public properties
@Published var name = ""
var isFormInvalid: Bool {
print("isFormInvalid")
return name.isEmpty
}
}
}
struct ChildView: View {
@ObservedObject private var viewModel: ViewModel
init(viewModel: ViewModel = ViewModel()) {
self.viewModel = viewModel
}
var body: some View {
Form {
Section(header: Text("Name")) {
nameTextField
}
Button {} label: {
Text("ChildIsValid?: \(String(!viewModel.isFormInvalid))")
}
.disabled(viewModel.isFormInvalid)
}
}
private var nameTextField: some View {
TextField("Add name", text: $viewModel.name)
.autocapitalization(.words)
}
}
struct ChildView_Previews: PreviewProvider {
static var previews: some View {
let vm = ChildView.ViewModel()
ChildView(viewModel: vm).preferredColorScheme(.light)
}
}
谢谢!
【问题讨论】:
-
不要为
isFormValid使用计算属性,使其成为@Published属性,并在name属性上使用didSet来设置isFormValid。 -
但是如何处理多个字段?
-
您需要在模型中创建一个
validate函数,并在任何属性发生变化时调用它。
标签: ios swift mvvm swiftui combine