Swiftui - How to Initialize an Observedobject Using an Environmentobject as a Parameter

Swiftui - How do I initialize an observedObject using an environmentobject as a parameter?

Here is the approach (the simplest IMO):

struct MyCoolView: View {
@EnvironmentObject var userData: UserData

var body: some View {
MyCoolInternalView(ViewObject(id: self.userData.UID))
}
}

struct MyCoolInternalView: View {
@EnvironmentObject var userData: UserData
@ObservedObject var viewObject: ViewObject

init(_ viewObject: ViewObject) {
self.viewObject = viewObject
}

var body: some View {
Text("\(self.viewObject.myCoolProperty)")
}
}

How to use EnvironmentObject to initialize State Property in SwiftUI?

EnvironmentObject is injected after view constructor call, so you have to initialize state to some default and reset it to desired value in top body view onAppear modifier, like

@EnvironmentObject var settings: Settings
@State var localAllowReminders: Bool = false // << just any default

var body: some View {
VStack { // << any top view
// ...
}
.onAppear {
self.localAllowReminders = settings.allowReminders // << here !!
}
}

Pass EnvironmentObject to an ObservableObject class

You should use @EnvironmentObject in your view and pass it down to your model if needed.

Here, struct updateEO is not a view.

I've created a simpler example to show you how to do this :

UserSettings

class UserSettings: ObservableObject {
@Published var info: String = ""
}

DownloadTimer

class DownloadTimer: ObservableObject {
var timer : Timer?

func start(settings: UserSettings) {
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { t in
settings.info = t.fireDate.description
}
}
}

And you call start (with UserSettings as parameter) when the Text appears.

MyView

struct MyView: View {
@StateObject private let downloadTimer = DownloadTimer()
@EnvironmentObject var settings: UserSettings

var body: some View {
Text(settings.info)
.onAppear {
self.downloadTimer.start(settings: self.settings)
}
}
}

And don't forget to call .environmentObject function to inject your UserSettings in SceneDelegate.

SceneDelegate

let contentView = MyView().environmentObject(UserSettings())

You should see the text updating as time goes by.

How to manage @ObservedObject and @EnvironmentObject on same Struct?

SwiftUI 2.0

Make it @StateObject, like

struct MenuView: View {

@EnvironmentObject var order: Order
@StateObject var model = DetailsModel()
...

SwiftUI 1.0

Inject it externally via constructor (having for it own life-cycle)

struct MenuView: View {

@EnvironmentObject var order: Order
@ObservedObject var model: DetailsModel
...

SwiftUI How to pass a global variable to non-View classes

Use a Singleton Pattern. Call UserSettings.sharedInstance from Categories & let contentView = ContentView().environmentObject(UserSettings.sharedInstance)

https://developer.apple.com/documentation/swift/cocoa_design_patterns/managing_a_shared_resource_using_a_singleton

SwiftUI: How to initialize a new StateObject in a parent view?

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

}
}


Related Topics



Leave a reply



Submit