0

I have an app architecture similar to the below (simplified) code. I use a WorkoutManager StateObject which I initialize in the set up view, then pass down to its children via EnvironmentObject. The problem is that upon dismissing the .sheet there isn't any life cycle event which initializes a new WorkoutManager, which I need in order to be able to start new workouts consecutively. How in this example below can I give WorkoutView the ability to reinitialize WorkoutManager so that it is a clean object?

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

    }
}
GarySabo
  • 5,806
  • 5
  • 49
  • 124
  • 2
    Dumb question, but can't you create a method inside WorkoutManager to reset it's state without creating a new instance? – Pastre Nov 08 '21 at 00:36
  • @Pastre not dumb at all but yes, my current solution right now is I have a resetWorkoutManager function inside workout manager which sets all of it's variables back to their initialized state. Just feels a little hacky and I wondered if there was a more SwiftUI way to do this. – GarySabo Nov 08 '21 at 00:50
  • 1
    @GarySabo a reset state func doesn't seem hacky at all to me – Steve M Nov 08 '21 at 03:46
  • 1
    @GarySabo "which sets all of its variables back in their initialized state" -- rather than setting all the variables, why not encapsulate the state in one `struct` that can be reset on the `WorkoutManager`? – jnpdx Nov 08 '21 at 04:49

1 Answers1

2

As mentioned in the comments already, the route you probably want to take is reseting the state within the same WorkoutManager. You wouldn't be able to assign a new object to a @StateObject anyway -- you'll end up with compiler errors because of the View's immutable self.

Secondly, I'd suggest that you probably don't want to rely on the Button in your WorkoutView to do this. For example, if the user dismissed the sheet by swiping, that wouldn't get called. Instead, you could listen for the sheet's state in onChange (another method would be using the onDismiss parameter of sheet):

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

    }
}
jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Thanks I should have clarified this is a WatchOS app so there isn't a way to dismiss the sheet other than the button. – GarySabo Nov 08 '21 at 00:51