SwiftUI:如何在父视图中初始化一个新的 StateObject?
SwiftUI: How to initialize a new StateObject in a parent view?
我有一个类似于以下(简化)代码的应用架构。我使用 WorkoutManager
StateObject
在设置视图中初始化,然后通过 EnvironmentObject
传递给它的子项。问题是,在关闭 .sheet
后,没有任何生命周期事件会初始化一个新的 WorkoutManager
,我需要它才能连续开始新的锻炼。在下面的这个例子中,我如何赋予 WorkoutView
重新初始化 WorkoutManager 的能力,使其成为一个干净的对象?
import SwiftUI
import HealthKit
class WorkoutManager: ObservableObject {
var workout: HKWorkout?
}
struct ContentView: View {
@StateObject var workoutManager = WorkoutManager()
@State var showingWorkoutView = false
var body: some View {
Button {
showingWorkoutView.toggle()
} label: {
Text("Start Workout")
}
.sheet(isPresented: $showingWorkoutView) {
WorkoutView(showingWorkoutView: $showingWorkoutView)
}
}
}
struct WorkoutView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var showingWorkoutView: Bool
var body: some View {
Text("Workout Started")
.padding()
Button {
showingWorkoutView.toggle()
//Here I want to initialize a new WorkoutManager to clear out the previous workout's state, how?
} label: {
Text("End Workout")
}
}
}
正如评论中已经提到的,您可能想要采用的方法是在同一个 WorkoutManager
中重置状态。无论如何,您都无法将 new 对象分配给 @StateObject
——由于 View
的不可变性,您最终会遇到编译器错误self
.
其次,我建议您可能不想依赖 WorkoutView
中的 Button
来执行此操作。例如,如果用户通过滑动关闭了 sheet
,则不会调用它。相反,您可以在 onChange
中监听 sheet
的状态(另一种方法是使用 sheet
的 onDismiss
参数):
class WorkoutManager: ObservableObject {
var workout: HKWorkout?
func resetState() {
//do whatever you need to do to reset the state
print("Reset state")
}
}
struct ContentView: View {
@StateObject var workoutManager = WorkoutManager()
@State var showingWorkoutView = false
var body: some View {
Button {
showingWorkoutView.toggle()
} label: {
Text("Start Workout")
}
.sheet(isPresented: $showingWorkoutView) {
WorkoutView(showingWorkoutView: $showingWorkoutView)
}
.onChange(of: showingWorkoutView) { newValue in
if !newValue {
workoutManager.resetState()
}
}
}
}
struct WorkoutView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var showingWorkoutView: Bool
var body: some View {
Text("Workout Started")
.padding()
Button {
showingWorkoutView.toggle()
} label: {
Text("End Workout")
}
}
}
我有一个类似于以下(简化)代码的应用架构。我使用 WorkoutManager
StateObject
在设置视图中初始化,然后通过 EnvironmentObject
传递给它的子项。问题是,在关闭 .sheet
后,没有任何生命周期事件会初始化一个新的 WorkoutManager
,我需要它才能连续开始新的锻炼。在下面的这个例子中,我如何赋予 WorkoutView
重新初始化 WorkoutManager 的能力,使其成为一个干净的对象?
import SwiftUI
import HealthKit
class WorkoutManager: ObservableObject {
var workout: HKWorkout?
}
struct ContentView: View {
@StateObject var workoutManager = WorkoutManager()
@State var showingWorkoutView = false
var body: some View {
Button {
showingWorkoutView.toggle()
} label: {
Text("Start Workout")
}
.sheet(isPresented: $showingWorkoutView) {
WorkoutView(showingWorkoutView: $showingWorkoutView)
}
}
}
struct WorkoutView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var showingWorkoutView: Bool
var body: some View {
Text("Workout Started")
.padding()
Button {
showingWorkoutView.toggle()
//Here I want to initialize a new WorkoutManager to clear out the previous workout's state, how?
} label: {
Text("End Workout")
}
}
}
正如评论中已经提到的,您可能想要采用的方法是在同一个 WorkoutManager
中重置状态。无论如何,您都无法将 new 对象分配给 @StateObject
——由于 View
的不可变性,您最终会遇到编译器错误self
.
其次,我建议您可能不想依赖 WorkoutView
中的 Button
来执行此操作。例如,如果用户通过滑动关闭了 sheet
,则不会调用它。相反,您可以在 onChange
中监听 sheet
的状态(另一种方法是使用 sheet
的 onDismiss
参数):
class WorkoutManager: ObservableObject {
var workout: HKWorkout?
func resetState() {
//do whatever you need to do to reset the state
print("Reset state")
}
}
struct ContentView: View {
@StateObject var workoutManager = WorkoutManager()
@State var showingWorkoutView = false
var body: some View {
Button {
showingWorkoutView.toggle()
} label: {
Text("Start Workout")
}
.sheet(isPresented: $showingWorkoutView) {
WorkoutView(showingWorkoutView: $showingWorkoutView)
}
.onChange(of: showingWorkoutView) { newValue in
if !newValue {
workoutManager.resetState()
}
}
}
}
struct WorkoutView: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var showingWorkoutView: Bool
var body: some View {
Text("Workout Started")
.padding()
Button {
showingWorkoutView.toggle()
} label: {
Text("End Workout")
}
}
}