对 SwiftUI 中的 @EnvironmentObject 感到困惑
Posted
技术标签:
【中文标题】对 SwiftUI 中的 @EnvironmentObject 感到困惑【英文标题】:Confusing about @EnvironmentObject in SwiftUI 【发布时间】: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 你能补充一点关于你面临的问题的信息吗?
【参考方案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 是否有效。以上是关于对 SwiftUI 中的 @EnvironmentObject 感到困惑的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:@Environment 未在视图层次结构中接收提供的值
SwiftUI:属性装饰器的理解@State,@Binding,@ObservedObject,@Published,@Environment,@EnvironmentObject
SwiftUI:属性装饰器的理解@State,@Binding,@ObservedObject,@Published,@Environment,@EnvironmentObject