alamodey
alamodey

Reputation: 14938

A View.environmentObject(_:) for may be missing as an ancestor of this view

I just updated to Xcode 11.4 and it's broken my code. I am storing some user settings in an ObservableObject as follows:

class UserSettings: ObservableObject {  
    @Published var cardOrder = UserDefaults.standard.integer(forKey: "Card Order")  
    @Published var cardTheme = UserDefaults.standard.integer(forKey: "Card Theme")  
    @Published var translation = UserDefaults.standard.integer(forKey: "Translation")  
    @Published var overdueFirst = UserDefaults.standard.bool(forKey: "Overdue First")  
    @Published var randomNum = 0  
}  

This is my main menu, the settings environment object is successfully passed down to the Settings view where I'm able to save and retrieve user selections.

struct ContentView: View {  
  @State var settings = UserSettings()  

  var body: some View {  
    SubView().environmentObject(settings)  
  }  
}  

struct SubView: View {  

  @EnvironmentObject var settings: UserSettings  

  var body: some View {  
    List {  
      NavigationLink (destination: Flashcard()){  
        HStack {  
          Image(systemName: "rectangle.on.rectangle.angled")  
          Text(verbatim: "Study")      
        }  
      }  

      NavigationLink (destination: Settings()) {  
        HStack {  
          Image(systemName: "gear")  
          Text(verbatim: "Settings")  
        }  
      }  
    }  
  }  
}  

But in my flashcard view, I am getting an error: Fatal error: No ObservableObject of type UserSettings found. A View.environmentObject(_:) for UserSettings may be missing as an ancestor of this view.: file SwiftUI, line 0

The error is on line 13 where I initiate Frontside. In the original code, I just called the Frontside subview, but I thought to solve the error I had to add .environmentObject(settings), but even after adding it my app compiles but crashes as soon I go to the Flashcard view.

struct Flashcard: View {  
  @EnvironmentObject var settings: UserSettings  

  @State var colour = UserDefaults.standard.integer(forKey: "Card Theme") * 6  
  @State private var showResults: Bool = false  
  @State private var fullRotation: Bool = false  
  @State private var showNextCard: Bool = false  


  var body: some View {  
    let zstack = ZStack {  

      Frontside(id: $settings.randomNum, sheet: $showingSheet, rotate: $fullRotation, invis: $showNextCard, col: $colour).environmentObject(self.settings)  
      //   


      Backside(id: $settings.randomNum, sheet: $showingSheet, bookmark: $bookmarked, results: $showResults, rotate: $fullRotation, invis: $showNextCard, col: $colour, trans: $translation).environmentObject(self.settings)  
    //  

    }  
  }  

Does anyone know what I'm doing wrong? This code compiled and ran fine in the previous Xcode.

Upvotes: 3

Views: 5909

Answers (4)

Raquel
Raquel

Reputation: 21

import SwiftUI

@main

// there is a file with the name of your "projectApp" (JuegosSwiftUIApp in my case)

struct JuegosSwiftUIApp: App { 
    var body: some Scene {
        WindowGroup {
            DatosIniciales() // any view
                .environmentObject(Datos()) // this solved it (Datos() is class type Observableobject) 
        }
    }
}

Upvotes: 0

lorem ipsum
lorem ipsum

Reputation: 29242

An @EnvironmentObject has to be filled with an @StateObject, an @ObservedObject or an ObservableObject directly NOT an @State

struct ContentView: View {  
    //@ObservedObject
    @StateObject var settings = UserSettings()  

    var body: some View {  
        SubView().environmentObject(settings)  
    }  
}  

Note: UserSettings has to be an ObservableObject

Apple documentation on managing model data

struct BookReader: App {
    @StateObject var library = Library()

    var body: some Scene {
        WindowGroup {
            LibraryView()
                .environmentObject(library)
        }
    }
}

struct LibraryView: View {
    @EnvironmentObject var library: Library

    // ...
}

Upvotes: 1

for coder in woods
for coder in woods

Reputation: 35

I'm running iOS 14.3 in the simulator and in my case the error was about my environmentObject NavigationController. It was resolved by modifying ContentView() with .environmentObject(NavigationController()) in the SceneDelegate and, if you want the preview to work, also in ContentView_Previews.

Upvotes: 1

Mohammad Rahchamani
Mohammad Rahchamani

Reputation: 5220

I think you should pass settings object to FlashCard and Settings as well. try this:

struct ContentView: View {  
  @State var settings = UserSettings()  

  var body: some View {  
    SubView().environmentObject(settings)  
  }  
}  

struct SubView: View {  

  @EnvironmentObject var settings: UserSettings  

  var body: some View {  
    List {  
      NavigationLink (destination: Flashcard().environmentObject(settings)){  
        HStack {  
          Image(systemName: "rectangle.on.rectangle.angled")  
          Text(verbatim: "Study")      
        }  
      }  

      NavigationLink (destination: Settings().environmentObject(settings)) {  
        HStack {  
          Image(systemName: "gear")  
          Text(verbatim: "Settings")  
        }  
      }  
    }  
  }  
}  

Upvotes: 3

Related Questions