【问题标题】:Confusing about @EnvironmentObject in SwiftUI对 SwiftUI 中的 @EnvironmentObject 感到困惑
【发布时间】:2019-11-21 07:22:39
【问题描述】:

我正在尝试在 SwiftUI 中练习 @EnvironmentObject 工具。
ContentView 中的共享对象 User init。
当我从 ContentView 切换到 NameView 时工作得很好。
但是,从 NameView 到 AgeView 失败了。 (请查看错误消息和代码会话)

错误信息

Fatal error: No ObservableObject of type User found.

有人可以给我建议吗?我错过了什么吗?谢谢

代码

init "User" type in contentView
NavigationView

+-----------+                   +--------+                   +-------+
|ContentView+--NavigationLink-->|NameView+--NavigationLink-->|AgeView|
+-----------+                   +--------+                   +-------+
final class User: ObservableObject {
    @Published var name: String
    @Published var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

struct ContentView: View {
    var user: User = User(name: "SomeName", age: 44)
    var body: some View {
        NavigationView {
            VStack {
                Text("name: \(self.user.name) age: \(self.user.age)")
                NavigationLink(destination: NameView().environmentObject(self.user)) {
                    Text("Show Name")
                }
            }
        }
    }
}

struct NameView: View {
    @EnvironmentObject var user: User
    var body: some View {
        VStack {
            Text("name: \(self.user.name)")
            NavigationLink(destination: AgeView()) {
                Text("Show Age")
            }
        }
    }
}

struct AgeView: View {
    @EnvironmentObject var user: User
    var body: some View {
        VStack {
            Text("age: \(self.user.age)")
        }
    }
}

【问题讨论】:

  • ContentView中的EnvironmentObject已经传递给SceneDelegate中的ContentView后,不需要再次传递给NameView
  • @MilenValchev 我知道并输入SceneDelegate 只是为了测试。
  • @CocoaUser 你能补充一点关于你面临的问题的信息吗?

标签: swift swiftui


【解决方案1】:

希望这可以帮助您了解以下示例:

我们的模型是Observable,并且所有变量已发布

class A: ObservableObject {
    @Published var id: String = ""
    @Published var value: String = ""
}

当将其用作 EnvironmentObject 时,请确保在 SceneDelegate.swift 中进行如下设置:

let example = Example()

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: example.environmentObject(A()))
        self.window = window
        window.makeKeyAndVisible()
    }

然后我们可以在所有视图中使用这个EnvironmentObject

struct Example: View {

    @EnvironmentObject var obj: A

    var body: some View {
        Button(action: {
            self.obj.value = "Hi im changed"
        }) {
            Text("Change me")
        }
    }
}

有时当你想更新这个对象中的数据时,xCode 可能会给你一个错误'No EnvironmentObject set for ... classname etc.',在这种情况下你需要传递一个 EnvironmentObject到目标视图:

DestinationView().environmentObject(self.A)

希望这会有所帮助,祝你好运!

【讨论】:

  • 谢谢。所以我需要在 SceneDelegate.swift 中初始化任何共享对象。对吗?
  • @CocoaUser - 不,仅当您想使用 EnvironmentObject 时。全局使用不需要的观察对象,可以在你的类/结构或你正在使用的任何东西中使用。
【解决方案2】:

您正在将 SceneDelegate 中的 EnvironmentObject 分配给 ContentView,因此 ContentView 的所有子视图都可以自动访问您的用户。

因此没有必要像这里一样再次传递它:NameView().environmentObject(self.user)

如果您在 .sheet 修饰符中显示 View ,您只需要再次传递 environmentObject ,因为它基本上是一个新的独立视图。

final class User: ObservableObject {
    @Published var name: String
    @Published var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

struct ContentView: View {
    @EnvironmentObject var user: User
    var body: some View {
        NavigationView {
            VStack {
                Text("name: \(self.user.name) age: \(self.user.age)")
                NavigationLink(destination: NameView()) {
                    Text("Show Name")
                }
            }
        }
    }
}

struct NameView: View {
    @EnvironmentObject var user: User
    var body: some View {
        VStack {
            Text("name: \(self.user.name)")
            NavigationLink(destination: AgeView()) {
                Text("Show Age")
            }
        }
    }
}

struct AgeView: View {
    @EnvironmentObject var user: User
    var body: some View {
        VStack {
            Text("age: \(self.user.age)")
        }
    }
}

【讨论】:

  • 我知道这只是为了测试以确保 AgeView 是否有效。
猜你喜欢
  • 1970-01-01
  • 2019-09-13
  • 2012-07-22
  • 2013-05-13
  • 2020-04-16
  • 2023-03-08
  • 2019-08-04
  • 2019-12-30
  • 2022-01-20
相关资源
最近更新 更多