当ObservedObject更改时,SwiftUI视图不会更新
我有一个内容视图,其中使用ForEach显示项目列表当ObservedObject更改时,SwiftUI视图不会更新,swift,xcode,mvvm,observable,swiftui,Swift,Xcode,Mvvm,Observable,Swiftui,我有一个内容视图,其中使用ForEach显示项目列表 @ObservedObject var homeVM : HomeViewModel var body: some View { ScrollView (.horizontal, showsIndicators: false) { HStack(spacing: 10) { Spacer().frame(width:8) ForEach(homeVM.favoriteS
@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)
}
而我的可观察对象
包含
@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)
}
有什么解释吗 我将从将结果转发到主队列开始,如下所示
DispatchQueue.main.async {
self.favoriteStores = (response)!.map(StoreViewModel.init)
}
接下来ForEach
跟踪id
参数,因此您应该确保以下结果具有不同的\U id
s,否则ForEach不会标记为需要更新
ForEach(homeVM.favoriteStores , id: \._id){ item in
StoreRowOneView(storeVM: item)
}
对于水平滚动视图,您需要固定高度,或者只使用条件滚动视图,当
someModels.count>0
var主体:一些视图{
滚动视图(.horizontal){
HStack(){
ForEach(someModels,id:\.someParameter1){someModel in
someView(someModel)
}
}.框架(高度:固定高度)
}
}
//或
var body:一些观点{
VStack{
如果someModels.count>0{
滚动视图(.horizontal){
HStack(){
ForEach(someModels,id:\.someParameter1){someModel in
someView(someModel)
}
}
}
}否则{
EmptyView()
//或其他观点
}
}
}
通过实现
func散列(放入散列程序:inout散列程序){
hasher.combine(某些参数1)
hasher.combine(某些参数2)
}
及
static func==(lhs:SomeModel,rhs:SomeModel)->Bool{
lhs.someParameter1==rls.someParameter1&&lhs.someParameter2==rls.someParameter2
}
并且还遵循@Asperi的建议,从模型中使用适当的id,该id对于每个元素都必须是唯一的
ForEach(someModels,id:\.someParameter1){someModel in
someView(someModel)
}
除了唯一ID之外,ForEach
没有其他方法通知更新
Text(someModels.count)
正在工作,因为它在更改计数时通知更改。分享一些可能有帮助的经验
当我使用ScrollView+ForEach+fetch时,在我通过其他方式触发视图刷新之前,不会显示任何内容。当我提供固定数据而不提取时,它正常显示。我通过为ScrollView指定.infinity width来解决这个问题
我的理论是,ForEach在fetch完成时重新呈现,但是ScrollView不知何故没有调整其宽度以适应内容
你的情况也是如此。通过提供固定宽度的文本,ForEach可以在初始化期间计算其宽度,ScrollView可以使用它来调整其宽度。但在fetch的情况下,ForEach的初始内容宽度为0,ScrollView也是如此。获取完成后,ScrollView不会相应地更新其宽度
给ScrollView一些初始宽度可以解决您的问题。什么是ItemStore?更重要的是
ForEach(homeVM.favoriteStores , id: \._id){ item in
StoreRowOneView(storeVM: item)
}
什么是\u id
我相信您的\u id
每次都是相同的,因此它不会更新列表。您必须将id:
某些变量放入列表中,以便在列表更改时重新呈现
更新:如果您没有任何其他变量将其值作为参考,那么您可以使用它
ForEach((0..<homeVM.favoriteStores.count)) { index in
StoreRowOneView(storeVM:: homeVM.favoriteStores[index])
}
ForEach((0..ForEach在它之外添加另一个文本时工作正常,这显示了存储的数量,因此id不是问题所在,对于DispatchQueue
,我认为我在主线程上,我不需要它,而且在添加文本后工作正常,这真的很奇怪,我面临着完全相同的问题。不过运气不好。我被困在我的t已持续数天。ViewModel在网络调用后更新,但列表在此之后停止更新。当我在网络调用后打印对象时,它会给我预期值,但视图不会更新。@Ishmeet更新我如果您找到了此问题的解决方案,请告诉我是否还没有找到解决方案。我认为这是一个SwiftUI错误。@Ishmeet-你们找到解决方案了吗现在解决了吗?我有同样的问题,但我使用列表视图。我的列表总是有两个单元格&这些单元格加载了正确的静态信息,当我点击Web服务并更新模型时,视图不再重新调整。当我打印模型对象时,它们会用最新的数据更新。如果你们发现了,请更新帖子solution@Dinakar我们确实通过重构找到了一个解决方案,以使用State/observeObject/Binding的正确组合。我们确保我们的对象作为State归父对象所有。但是,在向下游传递对象时,我们使用了Binding和observeObject属性包装器。WWDC的此视频帮助我们实现了以下结果:。如果您可以共享代码,我将我们可以帮得更好。你刚刚帮我节省了一吨时间。我正在做一个firebase项目,我也有同样的事情发生在我身上。谢谢!