ObservedObject 更改时 SwiftUI View 未更新

标签 swift xcode mvvm observable swiftui

我有一个内容 View ,我在其中使用 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!
    }
}

如果我直接填充数组,它工作正常,我可以看到商店列表
但是如果我在网络调用(后台作业)之后填充了数组,则 View 不会收到有更改的通知
 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)")
        }

但奇怪的是:
- 如果我添加一个显示数组项计数的文本, View 将得到通知并且一切正常

那就是我的意思 :
    @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 协议(protocol)

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)正在工作,因为它会在更改计数时通知更改。

关于ObservedObject 更改时 SwiftUI View 未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59754160/

相关文章:

ios - 如何使用 CustomStringConvertible 和 RawRepresentable 组合类型指定函数参数的类型?

c++ - typeid 运算符的奇怪行为?

cocoa - Mac 应用程序禁用 Xcode "Build and Archive"按钮。为什么?

xcode - 无法使用命令行工具运行 Swift 代码

c# - 复杂的ViewModel- View 无法根据需要的模型建议自动映射值。

c# - 使用 MVVM 模式中的 DXGrid 绑定(bind)/编辑数据的最佳选择是什么?

swift - UITableView 变量

swift - 如何在 Swift 中抑制返回类型为 Void 的闭包的隐式返回

ios - Swift iOS 内存使用量在运行时增加

wpf - 自定义控件只能实例化一次