问题描述
我的应用程序只有两个视图,两个视图都有自己的 viewmodel。 ViewA 显示和操作来自 selectednumbers 数组的对象。 ViewB 拥有所有可用的对象(数字)——在这个视图中,我想操作被 ViewA 使用的 selectednumbers 数组。
我试图找出如何在这两个 viewmodel 之间共享这些 selectednumbers 数组。我尝试使用 EnvironmentObject、StaticObject 等。但没有任何工作可以满足我的需要。我应该使用什么方法来达到预期的结果。感谢帮助!
import SwiftUI
struct ViewA: View {
@Observedobject var viewmodel = viewmodelA()
var body: some View {
vstack {
Text("\(viewmodel.number)")
.font(.largeTitle)
.padding()
.onTapGesture {
viewmodel.showNext()
}
ViewB()
}
}
}
class viewmodelA: ObservableObject {
var numbers: [Int] = []
@Published var number: Int
var index = 0
init() {
number = numbers.isEmpty ? 0 : numbers[index]
}
func showNext() {
guard !numbers.isEmpty else { return }
if index < numbers.count - 1 {
index += 1
} else {
index = 0
}
number = numbers[index]
}
}
struct ViewB: View {
@Observedobject var viewmodel = viewmodelB()
var body: some View {
HStack {
ForEach(viewmodel.numbers,id: \.self) { number in
Text("\(number)")
.foregroundColor(viewmodel.selectednumbers.contains(number) ? .red : .black)
.onTapGesture {
viewmodel.updateSelection(number)
}
}
}
}
}
class viewmodelB: ObservableObject {
@Published var numbers: [Int] = []
@Published var selectednumbers: [Int] = []
init() {
numbers.append(contentsOf: [1,2,3,4,5,6,7,8])
}
func updateSelection(_ number: Int) {
if selectednumbers.contains(number) {
selectednumbers.remove(number)
} else {
selectednumbers.append(number)
}
}
}
extension Array where Element: Equatable {
mutating func remove(_ object: Element) {
guard let index = firstIndex(of: object) else {return}
remove(at: index)
}
}
解决方法
你仍然可以保持逻辑分离,但你需要保持单一的事实来源,如果你想在视图之间共享数据,你要么需要传递 Bindings
或者您也可以在子视图之间共享 @ObservedObject
。
import SwiftUI
struct ViewA: View {
@ObservedObject var viewModel = ViewModelA(modelB: ViewModelB())
var body: some View {
VStack {
Text("\(viewModel.number)")
.font(.largeTitle)
.padding()
.onTapGesture {
viewModel.showNext()
}
ViewB(model: viewModel)
}
}
}
class ViewModelA: ObservableObject {
var numbers: [Int] = []
@Published var number: Int
@Published var modelB:ViewModelB
var index = 0
init(modelB:ViewModelB) {
self.modelB = modelB
number = numbers.isEmpty ? 0 : modelB.selectedNumbers[index]
}
func showNext() {
guard !modelB.selectedNumbers.isEmpty else { return }
if index < modelB.selectedNumbers.count - 1 {
index += 1
} else {
index = 0
}
number = modelB.selectedNumbers[index]
}
}
struct ViewB: View {
@ObservedObject var model : ViewModelA
var body: some View {
HStack {
ForEach(model.modelB.selectedNumbers,id: \.self) { number in
Text("\(number)")
.foregroundColor(model.modelB.selectedNumbers.contains(number) ? .red : .black)
.onTapGesture {
model.modelB.updateSelection(number)
}
}
}
}
}
struct ViewModelB {
var selectedNumbers: [Int] = []
init() {
selectedNumbers.append(contentsOf: [1,2,3,4,5,6,7,8])
}
mutating func updateSelection(_ number: Int) {
if selectedNumbers.contains(number) {
selectedNumbers.remove(number)
} else {
selectedNumbers.append(number)
}
}
}
extension Array where Element: Equatable {
mutating func remove(_ object: Element) {
guard let index = firstIndex(of: object) else {return}
remove(at: index)
}
}