当ObservedObject更改时,SwiftUI视图不会更新

当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

我有一个内容视图,其中使用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)
}
而我的
可观察对象
包含

@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项目,我也有同样的事情发生在我身上。谢谢!