Search code examples
swiftxcodeswiftuiios13

SwiftUI @EnvironmentObject error: may be missing as an ancestor of this view


my first view can get all the data from API request, then opened second view to change the API request data, it crashed.

below is the error

Fatal error: No ObservableObject of type NetworkManager found.
A View.environmentObject(_:) for NetworkManager may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-39.3/Core/EnvironmentObject.swift, line 55
2019-11-07 12:00:01.961425-0800 EarthQuake[73703:5913116] Fatal error: No ObservableObject of type NetworkManager found.
A View.environmentObject(_:) for NetworkManager may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-39.3/Core/EnvironmentObject.swift, line 55

This is swift file to fetch data from API, then save data to posts

import Foundation
import Combine

final class NetworkManager: ObservableObject {

    @Published var posts = [Post]()


    func fetchData() {

         //some code to fetch data, then save to posts

    }

}

In my first list view file: EarthQuakeList.swift


import SwiftUI

struct EarthQuakeList: View {

    @EnvironmentObject var networkManager: NetworkManager

    //@ObservedObject var networkManager = NetworkManager()

    var body: some View {

        NavigationView {
            List(networkManager.posts) { post in
                NavigationLink(destination: EarthQuakeDetail(detail: post.properties, location: post.locationCoordinate)) {
                    ListRow(magnitude: post.properties.mag ?? 0.0, place: post.properties.place)

                }

            }
          .navigationBarTitle(Text("Today"))      
            .navigationBarItems(

                    trailing:
                    VStack {

                        Button(action: {
                            print("Edit button tapped")
                            self.showEditPage.toggle()
                        }) {
                            //Top right icon
                            Image(systemName: "pencil.circle")
                                .resizable()
                                .frame(width: 20, height: 20, alignment: .center)
                        }.sheet(isPresented: $showEditPage) { 
                            return EditPage().environmentObject(self.networkManager)

                        }

                    }




            )



        }
        .onAppear {
            //Call function to fetch data
            self.networkManager.fetchData()
        }
    }
}

Everything works well, I can see all the data, but when I do the same thing in my second view file, I get the data back, but it does not update for the first view

In my second editing view file: EditPage.swift

import SwiftUI

struct EditPage: View {

    //@ObservedObject var networkManager = NetworkManager()

    @EnvironmentObject var networkManager: NetworkManager

    var body: some View {

        VStack {
            Text("Edite")


        }
        .onAppear(){

            //I called the same function to get data as in first view file, but it is not updating the list view 
            self.networkManager.fetchData()


        }

    }
}

SceneDelegate.swift

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        //Set up environment object
        let contentView = EarthQuakeList().environmentObject(NetworkManager())

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(
                rootView: contentView
            )
            self.window = window
            window.makeKeyAndVisible()
        }
    }

So I am expecting second view file to call function self.networkManager.fetchData() to get data from API call, then update list view in first swift file EarthQuakeList, the issue is I am just getting correct data back, the view is not updating with new data


Solution

  • The whole issue is very easy to fix just add self.networkManager @ EarthQuakeList.swift

    .sheet(isPresented: $showEditPage) { 
                                return EditPage().environmentObject(self.networkManager)
    

    I got the reason and inspired from article: https://github.com/peterfriese/Swift-EnvironmentObject-Demo