1

I have a TabView with two child views - PageOneView and PageTwoView. I also have an @EnvironmentObject Data initialized in SceneDelegate. I also have a nested child for each of the PageOneView and PageTwoView. For PageTwoView the nested child is also a view and inside it I can access and modify @EnvironmentObject, and all of the top level views (PageOneView and PageTwoView) reflect the change. But for PageOneView the nested child is a class, not a view, and when I try to modify it within the child of PageOneView I get an error: Thread 1: Fatal error: No ObservableObject of type Data found. A View.environmentObject(_:) for Data may be missing as an ancestor of this view. Is there a way to change @EnvironmentObject from within nested child that is not a View, but a class?

struct AppView: View {
        
        @EnvironmentObject var data: Data
        
        var body: some View {
            TabView {
                PageOneView().environmentObject(data)
                    .tabItem {
                        Text("PageOne")
                    }
    
                PageTwoView().environmentObject(data)
                    .tabItem {
                        Text("PageTwo")
                    }
                
                
            }
        }
    }

struct PageTwoView: View {
    
    @EnvironmentObject var data: Data
    
    var body: some View {
        VStack {
            Text("Data: \(data.Name)")
            ChildView()//.environmentObject(data)
        }
    }
}

struct ChildView: View {
    
    @EnvironmentObject var data: Data
    
    var body: some View {
        VStack {
            Text("Data: \(data.Name)")
        
            Button(action: {
            self.updateData()
            }) {
                Text("Update Data")
            }
        
        }
    }
    
    func updateData() 
    {
        self.data.Name = "Updated Name"
        
    }
}

struct PageOneView: View {
    
    @EnvironmentObject var data: Data
    
    var body: some View {
        
        VStack {
            Text("Data: \(data.Name)")
        
            Button(action: {
            self.updateData()
            }) {
                Text("Update Data")
            }
        
        }
    }
    
    func updateData()
    {
        var child = Child()
        child.updateData()
        
    }
    
}

class Child: NSObject{

     @EnvironmentObject var data: Data
    
    func updateData()
    {
        data.Name = "Updated Name Again"
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Alina
  • 61
  • 5

1 Answers1

0

Here is corrected part (you don't need @EnvironmentObject wrapper in class, it is designed for View, your Data is a class itself, so you can pass its instance by reference to your Child)

    func updateData()
    {
        var child = Child(data: self.data)
        child.updateData()
        
    }
    
}

class Child: NSObject{

    let data: Data

    init(data: Data) {
      self.data = data
    }
    
    func updateData()
    {
        data.Name = "Updated Name Again"
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Asperi, could you please take a look at this question in regards to passing EnvironmentObject? TIA https://stackoverflow.com/questions/62824167/access-environment-object-from-uiviewcontrollerrepresentable-object – Alina Jul 10 '20 at 00:01