SwiftUI@EnvironmentObject错误:此视图的祖先可能已丢失
我的第一个视图可以从API请求中获取所有数据,然后打开第二个视图更改API请求数据,它崩溃了 下面是错误SwiftUI@EnvironmentObject错误:此视图的祖先可能已丢失,swift,xcode,swiftui,ios13,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.
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获取数据,然后将数据保存到POST
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()
}
}
}
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()
}
}
}
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()
}
}
.sheet(isPresented: $showEditPage) {
return EditPage().environmentObject(self.networkManager)
一切正常,我可以看到所有的数据,但当我在第二个视图文件中执行相同的操作时,我会将数据取回,但第一个视图中的数据不会更新
在我的第二个编辑视图文件中:EditPage.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()
}
}
}
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()
}
}
}
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()
}
}
.sheet(isPresented: $showEditPage) {
return EditPage().environmentObject(self.networkManager)
SceneDelegate.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()
}
}
}
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()
}
}
}
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()
}
}
.sheet(isPresented: $showEditPage) {
return EditPage().environmentObject(self.networkManager)
所以我希望第二个视图文件调用函数self.networkManager.fetchData(),从API调用中获取数据,然后更新第一个swift文件中的列表视图,视图未使用新数据更新此问题似乎是由于在代码中使用了两个
NetworkManager
实例造成的
如果将此行添加到网络管理器中
:
final类网络管理器:{
静态let shared=NetworkManager()
}
然后更新两个视图中的引用,如下所示:
结构地震列表:{
@ObservedObject var networkManager=networkManager.shared
…
}
结构编辑页:{
@ObservedObject var networkManager=networkManager.shared
…
}
这将确保两个视图使用完全相同的对象访问信息。通过使用相同的对象,一个视图中的更新将导致另一个视图也被更新
一旦成功,我建议在SwiftUI中使用.environmentObject()
(),因为这样可以在应用程序中共享这些服务类型的相同实例
祝你的项目好运 整个问题很容易解决,只需添加self.networkManager@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()
}
}
}
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()
}
}
}
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()
}
}
.sheet(isPresented: $showEditPage) {
return EditPage().environmentObject(self.networkManager)
我从文章中得到了原因和启发:
如果您使用的是sheet ore导航,您必须传递环境对象,这可能是swiftUI的一个错误,但在Xcode 11.5中它对我有效:
.sheet(isPresented: $show){
mySheetView().environmentObject(self.myEnviromentObject)
}
请参阅本文中的“我的代码”,了解刷新2d中正在编辑的第一个视图的方法。希望对您有所帮助。@Asperi我使用的编码方式与您相同。ObservedObject和ObservedObject正如我从您的示例中看到的,您不需要—并没有任何东西强迫视图刷新。注意刷新状态是如何使用的。嗨@herzi,这很有效!非常感谢你!你是最棒的。我刚刚更新了我的问题,有
.environmentObject()
,但是第二个视图没有更新第一个视图,它崩溃了,你能看一下吗?下一个问题的建议是:尝试发布一个新问题(可能在评论中链接它)。这样,其他人仍然可以要求“接受”响应。我正在使用此单例设计模式,我面临的问题是,这在当时没有解决。我正在使用此解决方案将environmentObject添加到我的.sheet中。但是,在我的.sheet中,我有指向进一步视图的导航链接。似乎我必须使用上面的解决方案,通过NavigationLink层次结构将environmentObject传递给每个后续视图,否则会导致无法观察到的对象崩溃。我本以为来自父.sheet的后续视图将是.sheet的子视图,从而继承环境对象,但事实似乎并非如此。有人对此有什么想法吗?OP的EarthQuakeList.swift与此回复中的建议完全相同。是否有人可以将问题和回答回填,以便为比较提供依据?OP的问题没有它是没有价值的。碰巧这些bug会被列在哪里/报告?你的解决方案为我解决了这个问题,但我没有正式的地方可以参考。你知道这可能在哪里吗?