[英]SwiftUI: @ObservedObject redraws every view
我嘗試在 SwiftUI 中正確實現 MVVM 方式,所以我想出了這個(簡化的)Model 和 ViewModel:
struct Model {
var property1: String
var property2: String
}
class ViewModel: ObservableObject {
@Published var model = Model(property1: "this is", property2: "a test")
}
在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())
}
}
現在在其中一個TextField
中輸入文本會導致重繪我的 window 中的每個View
:打印 output 是:
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
...
如我所見, SwiftUI 重繪每個視圖,因為每個視圖都在監聽ObservedObject
。
我怎么能告訴 SwiftUI,它只應該重繪那些視圖,真正發生了什么變化?
實際上 MVVM 意味着每個視圖都有自己的 model,它會在 model 更改時更新,而不是所有視圖都有一個model。
所以不需要在ParentView
中觀察viewModel
因為它不依賴它
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)
}
}
另一種方法是分解視圖 model 以便每個視圖都有自己的視圖子模型,它將管理自己視圖的更新。
如果您的所有視圖都觀察到相同的事物,並且該事物發生了變化,那么您的所有視圖都將重新渲染。 這是根據定義。 沒有選項可以配置為選擇性地更新某些視圖。
話雖如此,您可以通過操縱要發布的更改來解決它。
例如;
class ViewModel: ObservableObject {
@Published var model = Model(property1: "this is", property2: "a test")
var mytext = "some text" // pass this as binding instead of model.propertyX
}
現在,當 textfield 更改時, mytext
會更改,但不會發布此更改,因此不會觸發進一步的視圖更新。 您仍然可以從 model 視圖訪問它。
我個人建議使用@State和@EnvironmentObject而不是“視圖模型”。 它們是處理綁定和查看更新的內置方法,具有大量安全防護和支持。
此外,您應該盡可能使用值類型而不是引用類型。 其他語言的 MVVM 沒有考慮到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.