簡體   English   中英

SwiftUI:@ObservedObject 重繪每個視圖

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM