Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Fatal error: No ObservableObject of type " " found and @EnvironmentObject error: may be missing as an ancestor of this view

Tags:

ios

swift

swiftui

Details about goal: I want to fetch data from firebase, list the data in rows in the format of question and answer. The answer will have a textfield to update it. There is a save button that will save the answers by uploading the question and answers to firebase.

Expectation vs results: Expected a button in my main menu when tapped to navigate to the screen. The result is my app freezes, and in the console I get the following error.

Error

Fatal error: No ObservableObject of type AllQuestionsAndAnswersClass found.
A View.environmentObject(_:) for AllQuestionsAndAnswersClass may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-39.4.4/Core/EnvironmentObject.swift, line 55
2020-01-24 13:21:25.523326-0600 FirebaseStarterApp[5025:894100] Fatal error: No ObservableObject of type AllQuestionsAndAnswersClass found.
A View.environmentObject(_:) for AllQuestionsAndAnswersClass may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-39.4.4/Core/EnvironmentObject.swift, line 55

My Thoughts I'm not too sure where to start but I think it has to do with having to add the environment object to the preview and do something in App Delegate. I have seen somethings about Scene Delegate but I only have App Delegate, I'm not sure if there is a difference

What I have tried I have tried to look at the following links but they did not help for my case SwiftUI @EnvironmentObject error: may be missing as an ancestor of this view

No ObservableObject of type found

Here is my code for the SwiftUI Screen

@available(iOS 13.0, *)
final class AllJobDataClass: ObservableObject  {
    @Published var allJobDataArray = [JobInfo]()
}

@available(iOS 13.0, *)
final class AllQuestionsAndAnswersClass: ObservableObject  {
    @Published var questionsAndAnswersInfoArray = [QuestionAndAnswer]()
}

@available(iOS 13.0.0, *)
struct SingleQuestionAndAnswerRow: View {

     @State var singleQuestionAndAnswerVar: QuestionAndAnswer

     var body: some View {

       return HStack{
             Text("\(singleQuestionAndAnswerVar.question)")

             TextField("Enter some text", text: $singleQuestionAndAnswerVar.answer)
                 .border(Color.black)
         }
     }
}


@available(iOS 13.0.0, *)
struct NewQuestionsScreenSwiftUIView: View {

    @EnvironmentObject var allJobDataVar: AllJobDataClass
    @EnvironmentObject var allQuestionsAndAnswerVar: AllQuestionsAndAnswersClass

    init()
    {
        fetchDataFromFirebase()
    }

    var body: some View {
        ScreenBackground
        {
            List(self.allQuestionsAndAnswerVar.questionsAndAnswersInfoArray) { questionAndAnswer in
                    //here is where questionAnswerRow is presented
                SingleQuestionAndAnswerRow(singleQuestionAndAnswerVar: questionAndAnswer)

                }
        }
        .onTapGesture {
            self.endEditingFunction()
        }
    }
}

@available(iOS 13.0.0, *)
struct NewQuestionsScreenSwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        NewQuestionsScreenSwiftUIView()
    }
}

My code for App Delegate

import UIKit
import Firebase
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Window setup
        FirebaseApp.configure()
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = UINavigationController(rootViewController: ATCClassicLandingScreenViewController(nibName: "ATCClassicLandingScreenViewController", bundle: nil))
        window?.makeKeyAndVisible()

        return true
    }
  }
like image 708
platypus Avatar asked Jan 24 '20 19:01

platypus


1 Answers

You have declarations for environment objects as

struct NewQuestionsScreenSwiftUIView: View {
    @EnvironmentObject var allJobDataVar: AllJobDataClass
    @EnvironmentObject var allQuestionsAndAnswerVar: AllQuestionsAndAnswersClass

but you must inject them somewhere before NewQuestionsScreenSwiftUIView usage, say on creation (or implicitly via parent view). In provided code it is not visible where you create NewQuestionsScreenSwiftUIView(), but in that place it should be something like

NewQuestionsScreenSwiftUIView()
    .environmentObject(AllJobDataClass()) // < or instance if created before
    .environmentObject(AllQuestionsAndAnswersClass()) // < or instance if created before
like image 175
Asperi Avatar answered Nov 04 '22 23:11

Asperi