Swift中两个ViewModel之间的共享绑定

aydmsdu9  于 2022-11-21  发布在  Swift
关注(0)|答案(1)|浏览(266)

我刚刚开始使用SwiftUI,我想使用ViewModels来封装我的逻辑,并将其与视图分离。
现在我刚刚遇到了我的第一个路障,我不知道如何通过这个。
所以到目前为止我的应用程序相当简单。我有两个视图,每个视图都有自己的ViewModel:ParentChild中的一个或多个。
Parent ViewModel保存了一个Item的列表,这些列表是从后端API中获取的。我想把它传递给Child及其ViewModel,因为它负责把Item添加到列表中。
下面是简化的代码:

struct ParentView: View {
  @StateObject private var viewModel = ViewModel()
  var body: some View {
    VStack {
      ChildView()
      Text("Items: \(viewModel.items.count)")
    }
  }
}

extension ParentView {
  @MainActor class ViewModel: ObservableObject {
    @Published var items: [Item] = []
  }
}

struct ChildView: View {
  @StateObject private var viewModel = ViewModel()
  var body: some View {
    List {
      ForEach(viewModel.items) { item in
        Text(item.name)
      }
    }
    .toolbar {
      ToolbarItem(placement: .navigationBarTrailing) {
        Button {
          viewModel.AddItem()
        } label: {
          Label("Add item", systemImage: "plus")
        }
      }
    }
  }
}

extension ChildView {
  @MainActor class ViewModel: ObservableObject {
    @Published var items: [Item] = []
    func AddItem() {
      items.append(Item(name: "Test"))
    }
  }
}

我如何才能使来自父视图模型的项目列表传递到子视图模型,确保只有一个列表,同时确保当该列表更改时两个视图都得到刷新?
谢谢你!

gzjq41n4

gzjq41n41#

你必须在你的ParentView中只有一个事实来源,然后你将它传递给子视图。目前你有多个ViewModel,它们彼此没有关系。
ChildView中,将@StateObject private var viewModel = ViewModel()替换为@ObservedObject var viewModel: ViewModel,在ParentView中,使用ChildView(viewModel: viewModel)ViewModel传递给它。
同时拆下extension ChildView ...并将@MainActor class ViewModel: ObservableObjectextension ParentView中取出。
请查看此链接,其中提供了一些很好的示例,说明如何使用ObservableObject以及如何在应用https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app中管理数据
编辑-1:
下面是我的完整测试示例代码,展示了如何将父视图模型传递给子视图...ensuring that there is only a single list, while also making sure that both views get refreshed when this list changes

struct ContentView: View {
    var body: some View {
        NavigationStack { // <-- here
            ParentView()
        }
    }
}

struct Item: Identifiable {
    let id = UUID()
    var name:String
}

struct ParentView: View {
    @StateObject var viewModel = ViewModel() // <-- here
    
    var body: some View {
        VStack {
            ChildView(viewModel: viewModel)  // <-- here
            Text("Items: \(viewModel.items.count)")
        }
    }
}

// -- here
@MainActor class ViewModel: ObservableObject {
    @Published var items: [Item] = [Item(name: "item-1"), Item(name: "item-2")]
}

struct ChildView: View {
    @ObservedObject var viewModel: ViewModel // <-- here
    
    var body: some View {
        List {
            ForEach(viewModel.items) { item in
                Text(item.name)
            }
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button {
                    viewModel.items.append(Item(name: "Test")) // <-- here
                } label: {
                    Label("Add item", systemImage: "plus")
                }
            }
        }
    }
}

相关问题