![](/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.