问题和解决
最近开始学习Swift的一些高阶知识,遂计划在写了一半的小项目中使用@EnvironmentObject来代替@Binding。
在替换的过程中,大部分的View都work perfectly fine,然而每当点开某个View时就会引发崩溃,并且报错:
A view is missing an environment object of type Cart. Ensure views relying on environment objects have the objects inserted such as with `.environmentObject(Cart())`经过一番寻找发现这个View是在一个.fullScreenCover中引出的,而不是常规的子View。
原始定义为:
.fullScreenCover(isPresented: $showCheckoutView, content: {
CheckoutView(isTakingOrder: $showCheckoutView)
})经过修改后的定义为
.fullScreenCover(isPresented: $showCheckoutView, content: {
CheckoutView(isTakingOrder: $showCheckoutView)
.environmentObject(cart)
})也就是在原来的基础上再次显式地传递了一次.environmentObject()。
原因
ChatGPT给出的理由
问:会不会是.fullScreenCover导致了这个问题?
答:在使用 .fullScreenCover 时可能会导致环境对象无法正确传递给子视图,从而引发 “A view is missing an environment object” 的错误提示。这是因为 .fullScreenCover 是一个全屏覆盖的视图,它会在一个新的视图层级中显示,并且可能会导致环境对象的传递出现问题。
问:是不是当子视图以闭包的形式存在时,它不能够自动的得到其父视图存在的@EnvironmentObject值,我必须显式地再次传递一次?
答:是的,您在闭包中创建的视图可能无法自动获得其父视图中存在的 @EnvironmentObject 值,因此您需要在闭包内显式地再次传递环境对象。这是因为闭包在创建视图时会捕获其创建时的环境状态,并且这个环境状态在闭包内部是不会自动更新的。因此,当您在闭包内创建视图时,这些视图可能无法自动获取父视图中的 @EnvironmentObject 值。要在闭包中访问环境对象,您可以使用 .environmentObject() 修饰符,并将环境对象传递给闭包内创建的视图。
struct ParentView: View {
@EnvironmentObject private var cart: Cart
var body: some View {
// 在闭包中创建子视图
VStack {
Text("Parent View")
ChildView()
.environmentObject(cart) // 显式传递环境对象
}
}
}
struct ChildView: View {
@EnvironmentObject private var cart: Cart
var body: some View {
VStack {
Text("Child View")
// 在子视图内部可以直接访问环境对象
Text("Cart count: \(cart.count)")
}
}
}