SwiftUI @EnvironmentObject错误:作为该视图的祖先可能会丢失

时间:2019-11-07 06:19:38

标签: swift xcode swiftui ios13

我的第一个视图可以从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

这是一个快速文件,用于从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调用中获取数据,然后更新第一个快捷文件 EarthQuakeList 中的列表视图,问题是我只是返回正确的数据,视图未使用新数据更新

3 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:3)

如果使用片矿导航,则必须通过环境Object可能是swiftUI的错误,但它在Xcode 11.5中对我有用:

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

答案 2 :(得分:0)

此问题似乎是由于在代码中使用两个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),因为这样可以在您的应用程序中共享这些服务类型的相同实例。

祝您的项目好运!