Unable to access @EnvironmentObject from a child view constructed with a function

526 views Asked by At

I'm trying to pass an EnvironmentObject to child views but am having no luck with the following code.

struct ContentView: View {
  enum MyViews: Int, CaseIterable {

    case introView
    case viewOne
    case viewTwo

    var activeView: AnyView {
      switch self.rawValue {
        case 0: return AnyView(IntroView())
        case 1: return AnyView(ViewOne())
        case 2: return AnyView(ViewTwo())
        default: return AnyView(IntroView())
      }
    }

    @State var pageIndex = 0

    func content() -> MyViews? {
        let newPage = MyViews.init(rawValue: pageIndex)
        return newPage
    }
}

var body: some View {
   Group {
    content()?.activeView // Problem appears to lie here
   }
   .environmentObject(userData)
}

If I replace content()?.activeView with a simple view e.g. TestView() then I'm able to successfully print out the userData variable in TestView(). But as it stands, I get a crash when trying to access userData in ViewOne(), even when ViewOne is identical to TestView().

Any idea what I'm doing wrong?

1

There are 1 answers

2
davidev On BEST ANSWER

The problem is that you need to pass your EnvironmentObject manually via init() to your viewModel. It won't be injected automatically. Here is a approach how to do it

func getActiveView(userData: UserData) -> AnyView {
    switch self.rawValue {
    case 0: return AnyView(IntroView(userData: userData))
      case 1: return AnyView(ViewOne())
    default: return AnyView(IntroView(userData: userData))
    }
}

In your View of ContentView call the function and pass the userData

ZStack {
    content()?
        .getActiveView(userData: userData)
        .environmentObject(userData)
}

IntroView and ViewModel take userData as parameter

class AListViewModel: ObservableObject {
    
    var userData: UserData
    init(userData: UserData) {
        self.userData = userData
    }

    func myFunc(){
        print("myVar: \(userData.myVar)")
    }
}

struct IntroView: View {
    @EnvironmentObject var userData: UserData
    
    @ObservedObject var someListVM : AListViewModel
    
    init(userData: UserData) {
        someListVM = AListViewModel(userData: userData)
    }