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
Pod Install Is Staying on "Setting Up Cocoapods Master Repo"
Uicollectionview Spacing Margins
Refresh Devices in Team Provisioning Profile Managed by Xcode 7
Swift - How to Hide Back Button in Navigation Item
App Installation Failed Due to Application-Identifier Entitlement
Xcode iOS Project Only Shows "My MAC 64-Bit" But Not Simulator or Device
Programmatically Scroll a Uiscrollview
When How to Activate/Deactivate Layout Constraints
Why Push Notifications Is Not Working on Testflight
Save and Load from Keychain | Swift
Uitableview Dynamic Cell Heights Only Correct After Some Scrolling
How to Make View the Size of Another View in Swiftui
Custom Font Sizing in Xcode 6 Size Classes Not Working Properly with Custom Fonts
Programmatically Dial a Phone Number and Pass Dtmf Using the iPhone Sdk
How to Convert a Nib-Based Project to a Storyboard-Based
Uicollectionview's Cell Registerclass in Swift
Nsdata Won't Accept Valid Base64 Encoded String
How to Apply a Vignette Cifilter to a Live Camera Feed in iOS