Reputation: 1429
I'm trying practice @EnvironmentObject
tool in SwiftUI.
the share object User
init in ContentView
.
When I switch from ContentView to NameView work very well.
But, from NameView to AgeView is failed. (take a look error message and Code session, please)
Error message
Fatal error: No ObservableObject of type User found.
Could someone give me advice? Do I miss something? thx
Code
init "User" type in contentView
NavigationView
+-----------+ +--------+ +-------+
|ContentView+--NavigationLink-->|NameView+--NavigationLink-->|AgeView|
+-----------+ +--------+ +-------+
final class User: ObservableObject {
@Published var name: String
@Published var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
struct ContentView: View {
var user: User = User(name: "SomeName", age: 44)
var body: some View {
NavigationView {
VStack {
Text("name: \(self.user.name) age: \(self.user.age)")
NavigationLink(destination: NameView().environmentObject(self.user)) {
Text("Show Name")
}
}
}
}
}
struct NameView: View {
@EnvironmentObject var user: User
var body: some View {
VStack {
Text("name: \(self.user.name)")
NavigationLink(destination: AgeView()) {
Text("Show Age")
}
}
}
}
struct AgeView: View {
@EnvironmentObject var user: User
var body: some View {
VStack {
Text("age: \(self.user.age)")
}
}
}
Upvotes: 3
Views: 3482
Reputation: 1657
Hope this helps you with the following example:
We have our model which is Observable and has all it's variables Published:
class A: ObservableObject {
@Published var id: String = ""
@Published var value: String = ""
}
When using it as an EnvironmentObject make sure you'd set this in the SceneDelegate.swift as follows:
let example = Example()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: example.environmentObject(A()))
self.window = window
window.makeKeyAndVisible()
}
Then we can use this EnvironmentObject in all Views:
struct Example: View {
@EnvironmentObject var obj: A
var body: some View {
Button(action: {
self.obj.value = "Hi im changed"
}) {
Text("Change me")
}
}
}
Sometimes when you want to update data in this object, xCode may give you an error about 'No EnvironmentObject set for ... classname etc.', in this case you need to pass an EnvironmentObject to the destination view:
DestinationView().environmentObject(self.A)
Hope this helps, goodluck!
Upvotes: 4
Reputation: 2738
Your are assigning the EnvironmentObject in your SceneDelegate to ContentView, so all subviews of ContentView automatically can access your User.
Passing it again is therefore unnecessary like here: NameView().environmentObject(self.user)
You only need to pass the environmentObject again if you show a View inside a .sheet modifier because its basically a new independent view.
final class User: ObservableObject {
@Published var name: String
@Published var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
struct ContentView: View {
@EnvironmentObject var user: User
var body: some View {
NavigationView {
VStack {
Text("name: \(self.user.name) age: \(self.user.age)")
NavigationLink(destination: NameView()) {
Text("Show Name")
}
}
}
}
}
struct NameView: View {
@EnvironmentObject var user: User
var body: some View {
VStack {
Text("name: \(self.user.name)")
NavigationLink(destination: AgeView()) {
Text("Show Age")
}
}
}
}
struct AgeView: View {
@EnvironmentObject var user: User
var body: some View {
VStack {
Text("age: \(self.user.age)")
}
}
}
Upvotes: 0