SwiftUI:@ObservedObject 重绘每个视图

Lup*_*rus 6 swift swiftui

我尝试在 SwiftUI 中正确实现 MVVM 方式,所以我想出了这个(简化的)模型和 ViewModel:

struct Model {
    var property1: String
    var property2: String
}

class ViewModel: ObservableObject {

    @Published var model = Model(property1: "this is", property2: "a test")

}
Run Code Online (Sandbox Code Playgroud)

在 a 中使用它View效果很好,但我遇到了一些糟糕的性能问题,因为我ViewModel用一些计算属性和一些函数扩展了它(而且它Model本身更复杂)。但让我们继续看这个例子,因为它完美地展示了我认为 SwiftUI 本身的一个大问题。

想象一下,您有这些视图来显示数据:

struct ParentView: View {

    @ObservedObject var viewModel: ViewModel

    var body: some View {
        print("redrawing ParentView")
        return ChildView(viewModel: self.viewModel)
    }
}

struct ChildView: View {

    @ObservedObject var viewModel: ViewModel

    var body: some View {
        print("redrawing ChildView")
        return VStack {
            ViewForTextField(property: self.$viewModel.model.property1)
            ViewForTextField(property: self.$viewModel.model.property2)
        }
    }

}

struct ViewForTextField: View {

    @Binding var property: String

    var body: some View {
        print("redrawing textView of \(self.property)")
        return TextField("...", text: self.$property)
            .textFieldStyle(RoundedBorderTextFieldStyle())
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,在其中一条TextField线索中输入文本,以重绘窗口中的每条线索! View打印输出为:

redrawing ParentView
redrawing ChildView
redrawing textView of this is
redrawing textView of a test
redrawing ParentView
redrawing ChildView
redrawing textView of this isa
redrawing textView of a test
redrawing ParentView
redrawing ChildView
redrawing textView of this isab
redrawing textView of a test
...
Run Code Online (Sandbox Code Playgroud)

正如我所看到的,SwiftUI 重绘了每个视图,因为每个视图都在监听ObservedObject.

我如何告诉 SwiftUI,它只应该重绘这些视图,到底在哪里发生了任何变化?

Asp*_*eri 0

实际上,MVVM 意味着每个视图都有自己的模型,该模型会根据模型更改进行更新,而不是所有视图都有一个模型。

所以不需要观察viewModelinParentView因为它不依赖于它

struct ParentView: View {

    var viewModel: ViewModel // << just member to pass down in child

    var body: some View {
        print("redrawing ParentView")
        return ChildView(viewModel: self.viewModel)
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是分解视图模型,以便每个视图都有自己的视图子模型,该子模型将管理自己视图的更新。