簡體   English   中英

當 ObservedObject 更改時,SwiftUI 視圖不會更新

[英]SwiftUI View does not updated when ObservedObject changed

我有一個內容視圖,其中使用 ForEach 顯示項目列表

@ObservedObject var homeVM : HomeViewModel

var body: some View {
    ScrollView (.horizontal, showsIndicators: false) {
        HStack(spacing: 10) {
            Spacer().frame(width:8)
            ForEach(homeVM.favoriteStores , id: \._id){ item in
                StoreRowOneView(storeVM: item)
            }
            Spacer().frame(width:8)
        }
    }.frame(height: 100)
}

我的ObservableObject包含

@Published var favoriteStores = [StoreViewModel]()

StoreViewModel定義如下

class StoreViewModel  : ObservableObject {
    @Published var store:ItemStore

    init(store:ItemStore) {
        self.store = store
    }

    var _id:String {
        return store._id!
    }
}

如果我直接填充數組,它工作正常,我可以看到商店列表,但如果我在網絡調用(后台作業)后填充數組,則視圖沒有收到更改通知

 StoreApi().getFavedStores(userId: userId) { (response) in
            guard response != nil else {
                self.errorMsg = "Something wrong"
                self.error = true
                return
            }
            self.favoriteStores = (response)!.map(StoreViewModel.init)
            print("counnt favorite \(self.favoriteStores.count)")
        }

但奇怪的是: - 如果我添加一個顯示數組項計數的文本,視圖將收到通知並且一切正常

那就是我的意思 :

    @ObservedObject var homeVM : HomeViewModel
    var body: some View {
        ScrollView (.horizontal, showsIndicators: false) {
            HStack(spacing: 10) {
                Spacer().frame(width:8)
                ForEach(homeVM.favoriteStores , id: \._id){ item in
                    StoreRowOneView(storeVM: item)
                }
                Text("\(self.homeVM.favoriteStores.count)").frame(width: 100, height: 100)
                Spacer().frame(width:8)
            }
        }.frame(height: 100)
    }

對此有任何解釋嗎?

對於水平 ScrollView,您需要固定高度或僅使用條件 ScrollView,它會在someModels.count > 0時顯示

var body: some View {
   ScrollView(.horizontal) {
      HStack() {
         ForEach(someModels, id: \.someParameter1) { someModel in
            someView(someModel)
         }
      }.frame(height: someFixedHeight)
   }
}
// or
var body: some View {
   VStack {
      if someModels.count > 0 {
         ScrollView(.horizontal) {
            HStack() {
               ForEach(someModels, id: \.someParameter1) { someModel in
                  someView(someModel)
               }
            }
         }
      } else {
        EmptyView()
        // or other view
      }
   }
}

通過實現正確符合 Hashable 協議

func hash(into hasher: inout Hasher) { 
   hasher.combine(someParameter1)
   hasher.combine(someParameter2)
}

static func == (lhs: SomeModel, rhs: SomeModel) -> Bool {
   lhs.someParameter1 == rls.someParameter1 && lhs.someParameter2 == rls.someParameter2

}

並且還遵循@Asperi 建議使用模型中的正確 id,它必須對每個元素都是唯一的。

ForEach(someModels, id: \.someParameter1) { someModel in
    someView(someModel)
}

ForEach沒有其他方法可以通知唯一 ID 以外的更新。

Text(someModels.count)正在工作,因為它會在更改計數時通知更改。

分享一些可能有幫助的經驗。

當我使用 ScrollView + ForEach + fetch 時,在我通過其他方式觸發視圖刷新之前不會顯示任何內容。 當我提供固定數據而不獲取時,它會正常顯示。 我通過為 ScrollView 指定 .infinity 寬度來解決它。

我的理論是 ForEach 在 fetch 完成時重新渲染,但 ScrollView 以某種方式不調整其寬度以適應內容。

你的情況類似。 通過提供固定寬度的 Text,ForEach 可以在 init 期間計算其寬度,而 ScrollView 可以使用它來調整其寬度。 但是在 fetch 的情況下,ForEach 的初始內容寬度為 0,ScrollView 也是如此。 當獲取完成時 ScrollView 不會相應地更新其寬度。

給 ScrollView 一些初始寬度應該可以解決你的問題。

我將從將結果轉發到主隊列開始,如下所示

DispatchQueue.main.async {
    self.favoriteStores = (response)!.map(StoreViewModel.init)
}

接下來... ForEach跟蹤id參數,所以你應該確保結果在下面有不同的_id ,否則 ForEach 沒有標記為需要更新

ForEach(homeVM.favoriteStores , id: \._id){ item in
    StoreRowOneView(storeVM: item)
}

什么是物品商店? 更重要的是

ForEach(homeVM.favoriteStores , id: \._id){ item in
    StoreRowOneView(storeVM: item)
}

什么是_id我相信你的_id每次都是一樣的,所以它不會更新列表。 你必須把id:一些變量,當它改變時你想重新呈現列表。

更新:如果您沒有任何其他變量將其值作為參考,則可以使用

ForEach((0..<homeVM.favoriteStores.count)) { index in
    StoreRowOneView(storeVM:: homeVM.favoriteStores[index])
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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