![](/img/trans.png)
[英]SwiftUI ObservedObject does not updated when new items are added from a different view
[英]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.