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 的状态(另一种方法是使用 sheetonDismiss 参数):

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")
        }

    }
}