SwiftUI:@Environment 未在视图层次结构中接收提供的值

Posted

技术标签:

【中文标题】SwiftUI:@Environment 未在视图层次结构中接收提供的值【英文标题】:SwiftUI: @Environment not receiving provided value down the view hierarchy 【发布时间】:2021-03-23 10:59:08 【问题描述】:

我正在按照 this project 的示例创建我的 ios 应用程序(感谢 Alexey!),但无法让 @Environment 变量接收正在向下传递 UI 层次结构的值。***视图接收正确的值,但下游视图接收default 值。

编辑:在复制 Asperi 的代码之后,我发现只有在通过NavigationLink 调用下游视图时才会发生这种行为。更新以下代码:

EDIT2:问题在于调用environment 方法的位置。在NavigationView 而不是MainView 上调用它解决了这个问题。代码更新如下:

自定义环境键 - DIContainer

struct DIContainer: EnvironmentKey 
    
    let interactor: Interactor
    
    init(interactor: Interactor) 
        self.interactor = interactor
    
    
    static var defaultValue: Self  Self.default 
    
    private static let `default` = Self(interactor: .stub)


extension EnvironmentValues 
    var injected: DIContainer 
        get  self[DIContainer.self] 
        set  self[DIContainer.self] = newValue 
    


App 结构体

private let container: DIContainer

init() 
    container = DIContainer(interactor: RealInteractor())


var body: some Scene 
    WindowGroup 
        NavigationView 
            MainView()
        
        .environment(\.injected, container)

主视图

struct MainView: View 

    @Environment(\.injected) private var injected: DIContainer
    // `injected` has the `RealInteractor`, as expected

    var body: some View 
        VStack 
            Text("Main: \(injected.foo())")  \\ << Prints REAL

            NavigationLink(destination: SearchView()) 
                Text("Search")
            
        
    

搜索视图

struct SearchView: View 

    @Environment(\.injected) private var injected: DIContainer
    // `injected` has the `StubInteractor`, why?

    var body: some View 
        Text("Search: \(injected.foo())")
    

我可以通过像这样修改MainView 来解决这个问题:

    var body: some View 
        SearchView()
            .environment(\.injected, container)
    

但是@Environment的目的不是避免重复这样做吗?

任何指导/指针表示赞赏。

【问题讨论】:

【参考方案1】:

我尝试复制所有部分并编译它们...结果按预期工作 - 环境在视图层次结构中向下传递,因此您可能会在实际代码中遗漏某些内容。

这是完整的模块,使用 Xcode 12.4 / iOS 14.4 测试

class Interactor                     // << replicated !!
    static let stub = Interactor()
    func foo() -> String  "stub" 


class RealInteractor: Interactor              // << replicated !!
    override func foo() -> String  "real" 


struct ContentView: View                   // << replicated !!
    private let container: DIContainer

    init() 
        container = DIContainer(interactor: RealInteractor())
    

    var body: some View 
        NavigationView 
            MainView()
        
        .environment(\.injected, container) // << to affect any links !!
    


// no changes in env parts
struct DIContainer: EnvironmentKey 

    let interactor: Interactor

    init(interactor: Interactor) 
        self.interactor = interactor
    

    static var defaultValue: Self  Self.default 

    private static let `default` = Self(interactor: .stub)


extension EnvironmentValues 
    var injected: DIContainer 
        get  self[DIContainer.self] 
        set  self[DIContainer.self] = newValue 
    


struct MainView: View 

    @Environment(\.injected) private var injected: DIContainer
    // `injected` has the `RealInteractor`, as expected

    var body: some View 
        SearchView()
    



// just tested here
struct SearchView: View 

    @Environment(\.injected) private var injected: DIContainer

    var body: some View 
        Text("Result: \(injected.interactor.foo())")     // << works fine !!
    

【讨论】:

哇!没想到任何人都会如此尽职尽责。谢谢!在我尝试复制回您的工作环境后,我发现我的 SearchViewNavigationLink 中被调用,这导致了问题。 NavigationView 上调用environment 方法解决了我的问题。您能否为未来的编码人员更新您的答案,我可以接受吗?

以上是关于SwiftUI:@Environment 未在视图层次结构中接收提供的值的主要内容,如果未能解决你的问题,请参考以下文章

我如何在swiftui中从我的应用程序中的任何视图访问这个:@Environment(\.managedObjectContext) var context? [关闭]

添加 ViewModel 后,SwiftUI 视图未在按钮切换上更新

SwiftUI @Binding 未在子项中更新

SwiftUI ChildView 未在状态更改时重新计算

视图模型中的 Firestore 方法未在 SwiftUI onAppear 方法中调用

音频未在 SwiftUI 中播放