使用Environment、EnvironmentObject遇到的问题

使用Environment、EnvironmentObject遇到的问题

 次点击
8 分钟阅读

问题和解决

最近开始学习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)")
        }
    }
}

© 本文著作权归作者所有,未经许可不得转载使用。