在SwiftUI中,我想将一个环境对象传递给视图模型,以便我可以更改/更新它。envimentobject是一个简单的AppState,由一个属性计数器组成。
class AppState: ObservableObject {
@Published var counter: Int = 0
}
视图模型"更新环境对象,如下所示:
class CounterViewModel: ObservableObject {
var appState: AppState
init(appState: AppState) {
self.appState = appState
}
var counter: Int {
appState.counter
}
func increment() {
appState.counter += 1
}
}
ContentView显示值:
struct ContentView: View {
@ObservedObject var counterVM: CounterViewModel
init(counterVM: CounterViewModel) {
self.counterVM = counterVM
}
var body: some View {
VStack {
Text("(counterVM.counter)")
Button("Increment") {
counterVM.increment()
}
}
}
}
我还注入了如下所示的状态:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
NavigationStack {
let appState = AppState()
ContentView(counterVM: CounterViewModel(appState: appState))
.environmentObject(appState)
}
}
}
问题是,当我点击增量按钮,反虚拟机。计数器永远不会返回更新后的值。我错过了什么?
你的类CounterViewModel
是一个ObservableObject,但它没有@Published
属性-所以没有任何更改将自动发布到视图
但是你可以使用objectWillChange.send()
:
func increment() {
objectWillChange.send()
appState.counter += 1
}
您检查了您的xxxxApp.swift
(以前是AppDelegate
)文件吗?有时Xcode会自动为你做,有时你不需要手动添加它,并添加你的环境对象。*它必须是包含所有你想要共享对象的视图。
var body: some Scene {
WindowGroup {
VStack {
ContentView()
.environmentObject(YourViewModel())
}
}
}
我们实际上并没有在SwiftUI中为视图数据使用视图模型对象。我们使用@State
结构体,如果我们需要在子视图中改变它,我们传递一个绑定,例如
struct Counter {
var counter: Int = 0
mutating func increment() {
counter += 1
}
}
struct ContentView: View {
@State var counter = Counter()
var body: some View {
ContentView2(counter: $counter)
}
}
struct ContentView2: View {
@Binding var counter: Counter // if we don't need to mutate it then just use let and body will still be called when the value changes.
var body: some View {
VStack {
Text(counter.counter, format: .number) // the formatting must be done in body so that SwiftUI will update the label automatically if the region settings change.
Button("Increment") {
counter.increment()
}
}
}
}
我不确定为什么CounterViewModel和AppState都需要是可观察对象,因为您正在使用视图模型来格式化模型的内容。我认为AppState是一个模型,因此我可以将其定义为一个结构体。CounterViewModel将会是ObservableObject并且它发布了AppState。这样你的代码就干净了,可以工作了。
AppState代码:import Foundation
struct AppState {
var counter: Int = 0
}
代码:
import SwiftUI
class CounterViewModel: ObservableObject {
@Published var appState: AppState
init(appState: AppState) {
self.appState = appState
}
var counter: Int {
appState.counter
}
func increment() {
appState.counter += 1
}
}
ContentView的代码:
import SwiftUI
struct ContentView: View {
@StateObject var counterVM = CounterViewModel(appState: AppState())
var body: some View {
VStack {
Text("(counterVM.counter)")
Button("Increment") {
counterVM.increment()
}
}
}
}
一定要提醒,在你第一次定义ObservableObject的视图中,你用@StateObject来定义它。在所有也将使用该对象的视图中,使用@ObservedObject。
这段代码可以运行。