Reputation: 165
I am new to swift programming. I was trying to play around with the environment object to update views by changing the value of the environment object specifically via a class function. I have two subviews in the contentview as I wish to see if both subviews get updated together when the string gets changed in UserData environment object.
However, there's an error saying 'Thread 1: Fatal error: No ObservableObject of type UserData found. A View.environmentObject(_:) for UserData may be missing ...'
In SceneDelagate.swift, I have injected the environment object:
let userData = UserData()
window.rootViewController = UIHostingController(rootView:contentView.environmentObject(userData))
UserData.swift
final class UserData: ObservableObject {
@Published var image: UIImage? = nil
@Published var string = ""
}
StringGenerator.swift
class StringGenerator {
@EnvironmentObject var userData: UserData
func changeURL(){
print("Changing string now from \(userData.string)")
if self.userData.string == "HELLO"{
self.userData.string = "BYE"
}
else{
self.userData.string = "HELLO"
}
print("to \(userData.string)")
}
}
SubView1.swift
struct SubView1: View {
@EnvironmentObject var userData: UserData
var body: some View {
Text("\(userData.string)")
}
}
SubView2.swift
struct SubView2: View {
@EnvironmentObject var userData: UserData
var body: some View {
Text("\(userData.string)")
}
}
ContentView.swift
struct ContentView: View {
@EnvironmentObject var userData: UserData
let stringGenerator = StringGenerator()
var body: some View {
VStack{
Button(action: {
print("Changing Text Now !")
self.stringGenerator.changeURL()
print("\(self.userData.string)")
}) {
Text("Change Text ")
}
SubView1()
SubView2()
}
}
}
In general, I wish to know how does one change the environment object via a class function.
The code crashes when I run it. What's the problem in here?
Upvotes: 2
Views: 1211
Reputation: 258057
Here is a solution:
1) in ContentView
struct ContentView: View {
@EnvironmentObject var userData: UserData
let stringGenerator: StringGenerator // declare-only
2) in generator
class StringGenerator {
var userData: UserData // just member
init(userData: UserData) {
self.userData = userData
}
3) in SceneDelegate
let userData = UserData()
// inject generator via constructor with same user data
let contentView = ContentView(stringGenerator:
StringGenerator(userData: userData))
window.rootViewController = UIHostingController(rootView:
contentView.environmentObject(userData))
Upvotes: 1