免責宣告: 我是 swift 的新手
我正在嘗試以這樣一種方式設定 MVVM 應用程式,即多個螢屏可以訪問單個視圖模型,但由于某種原因,每次我離開主頁時,都會重新創建視圖模型。ViewModel 是這樣設定的:
extension ContentView {
//view model
class MyViewModel: ObservableObject {
let sdk: mySdk
@Published var allProducts = [ProductItem]()
@Published var itemsArray = [Item]() //This gets updated with content later on
...
init(sdk: mySdk) {
self.sdk = sdk
self.loadProds(forceReload: false)
...
func loadProds(forceReload: Bool){
sdk.getProducts(forceReload: forceReload) { products, error in
if let products = products {
self.allProducts = products
} else {
self.products = .error (error?.localizedDescription ?? "error")
print(error?.localizedDescription)
}
}
...
//itemsArray gets values appended to it as follows:
itemsArray.append(Item(productUid: key, quantity: Int32(value)))
}
}
}
}
其余代碼設定如下:
struct ContentView: View { // Home Screen content
@ObservedObject var viewmodel: MyViewModel
var body: some View {
...
}
}
應該根據 itemsArray 的狀態更新的SecondView設定如下:
struct SecondView: View {
@ObservedObject var viewModel: ContentView.MyViewModel //I have also tried using @StateObject
init(sdk: mySdk) {
_viewModel = ObservedObject(wrappedValue: ContentView.MyViewModel(sdk: sdk))
}
var body: some View {
ScrollView {
LazyVStack {
Text("Items array count is \(viewModel.itemsArray.count)")
Text("All prods array count is \(viewModel.allProducts.count)")
if viewModel.itemsArray.isEmpty{
Text ("Items array is empty")
}
else {
Text ("Items array is not empty")
...
}
}
}
}
}
包含自定義 TabView 并處理 Navigation 的主視圖設定如下:
struct MainView: View {
let sdk = mySdk(dbFactory: DbFactory())
@State private var selectedIndex = 0
let icons = [
"house",
"cart.fill",
"list.dash"
]
var body: some View{
VStack {
//Content
ZStack {
switch selectedIndex {
case 0:
NavigationView {
ContentView(viewmodel: .init(sdk: sdk))
.navigationBarTitle("Home")
}
case 1:
NavigationView {
SecondView(sdk: sdk)
.navigationBarTitle("Cart")
}
...
...
}
}
}
}
}
每次我離開 ContentView 螢屏時,視圖模型的任何更新內容都會被重置。例如,在導航SecondView螢屏時 itemsArray.count顯示為 0,但allProducts Array 在預加載時顯示正確的值。ContentView的全部內容在回傳時也會重新創建。
我希望 ViewModel 中的資料在多個視圖上持續存在,除非明確要求重繪 。請問我該怎么做?我似乎無法弄清楚我在哪里做錯了什么。任何幫助將不勝感激。
uj5u.com熱心網友回復:
您對視圖模型的ContentView呼叫.init,因此每次 SwiftUI 的渲染系統需要重繪自己時,您都會獲得創建的視圖模型的新實體。同樣,init()方法 onSecondView也以它的ContentView.MyViewModel(sdk: sdk)形式呼叫 init 方法。
更好的方法是在層次結構的更上層創建一個實體,并將其存盤為@StateObjectSwiftUI 知道回應對其已發布屬性的更改。使用@StateObject 一次還可以顯示哪個視圖“擁有”該物件;只要該視圖在層次結構中,該實體就會一直存在。
在您的情況下,我將在其中創建您的視圖模型MainView——這可能意味著視圖模型定義不應在ContentView. 假設你改變命名空間,你會有類似的東西
struct MainView: View {
@StateObject private var viewModel: ViewModel
init() {
let sdk = mySdk(dbFactory: DbFactory())
let viewModel = ViewModel(sdk: sdk)
_viewModel = StateObject(wrappedValue: viewModel)
}
var body: some View{
VStack {
//Content
ZStack {
switch selectedIndex {
case 0:
NavigationView {
ContentView(viewModel: viewModel)
.navigationBarTitle("Home")
}
case 1:
NavigationView {
SecondView(viewModel: viewModel)
.navigationBarTitle("Cart")
}
...
...
}
}
}
}
}
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
// etc
}
}
struct SecondView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
// etc
}
}
關鍵的事情之一是它ObservedObject旨在監視視圖本身不擁有的物件的更改,因此您永遠不應該創建物件并將它們直接分配給@ObservedObject屬性。相反,它們應該接收對更高視圖所擁有的物件的參考,例如那些已經用 . 宣告的物件@StateObject。
uj5u.com熱心網友回復:
首先,let sdk = mySdk(dbFactory: DbFactory())應該是@StateObject var sdk = mySdk(dbFactory: DbFactory())。
要繼續,SecondView&ContentView應該具有相同的ViewModel,因此它們應該是這樣的:
ContentView(viewmodel: sdk)
SecondView(sdk: sdk)
也使用@StateObject代替@ObservedObject
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/486941.html
