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

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

我的第一个视图可以从 API 请求中获取所有数据,然后打开第二个视图来更改 API 请求数据,它崩溃了。

错误如下

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

这是 swift 文件,用于从 API 获取数据,然后将数据保存到帖子

import Foundation
import Combine

final class NetworkManager: ObservableObject {

    @Published var posts = [Post]()


    func fetchData() {

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

    }

}

在我的第一个列表视图文件中: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()
        }
    }
}

一切正常,我可以看到所有数据,但是当我在我的第二个视图文件中做同样的事情时,我得到了数据,但它不会为第一个视图更新

在我的第二次编辑视图文件中: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()
        }
    }

所以我希望第二个视图文件调用函数 self.networkManager.fetchData() 从 API 调用中获取数据,然后首先更新列表视图 swift 文件 EarthQuakeList,问题是我只是得到正确的数据,视图没有更新新数据

这个问题似乎是由于在您的代码中使用了两个 NetworkManager 实例引起的。

如果将此行添加到 NetworkManager:

final class NetworkManager: … {

    static let shared = NetworkManager()

}

然后像这样更新两个视图中的引用:

struct EarthQuakeList: … {

    @ObservedObject var networkManager = NetworkManager.shared

    …

}

struct EditPage: … {

    @ObservedObject var networkManager = NetworkManager.shared

    …

}

这将确保两个视图使用完全相同的对象来访问信息。通过使用相同的对象,一个视图中的更新将导致另一个视图也被更新。

一旦成功,我建议在 SwiftUI 中使用 .environmentObject() (example),因为这将允许在您的应用程序中共享这些服务类型的相同实例。

祝你项目顺利!

整个问题很容易解决,只需添加 self.networkManager @ EarthQuakeList.swift

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

我从文章中得到了原因和启发: https://github.com/peterfriese/Swift-EnvironmentObject-Demo

如果你正在使用 sheet 矿石导航,你必须传递环境对象,这可能是 swiftUI 的一个错误,但它适用于 Xcode 11.5:

.sheet(isPresented: $show){
        mySheetView().environmentObject(self.myEnviromentObject)
}