[英]SwiftUI @EnvironmentObject error: may be missing as an ancestor of this view -- accessing object in the init()
The following code produces the runtime error: @EnvironmentObject error: may be missing as an ancestor of this view.以下代码产生运行时错误:@EnvironmentObject 错误:可能作为此视图的祖先丢失。 The tState in the environment is an @ObservedObject.
环境中的 tState 是一个 @ObservedObject。
struct TEditorView: View {
@EnvironmentObject private var tState: TState
@State var name = ""
init() {
self._name = State(initialValue: tState.name)
}
var body: some View {
...
}
}
XCode 12.0.1 iOS 14 XCode 12.0.1 iOS 14
The answer is that an Environment Object apparently cannot be accessed in an init() function.答案是环境对象显然不能在 init() 函数中访问。 However, an ObservedObject can be.
但是,一个 ObservedObject 可以。 So I changed the code to this and it works.
所以我把代码改成了这个,它可以工作。 To make it easy I turned TState into a singleton that I could access anywhere.
为了方便起见,我将 TState 变成了一个可以在任何地方访问的单例。 This could probably replace the use of @EnvironmentObject in many situations.
在许多情况下,这可能会取代 @EnvironmentObject 的使用。
struct TEditorView: View {
@ObservedObject private var tState = TState.shared
//@EnvironmentObject private var tState: TState
@State var name = ""
init() {
self._name = State(initialValue: tState.name)
}
var body: some View {
...
}
}
A different approach here could be to inject the initial TState
value in the constructor and do-away with the @EnvironmentObject
completely.这里的另一种方法可能是在构造函数中注入初始
TState
值并完全取消@EnvironmentObject
。 Then from the parent view you can use the @EnvironmentObject
value when creating the view.然后从父视图中,您可以在创建视图时使用
@EnvironmentObject
值。
struct TEditorView: View {
@State var name = ""
init(tState: TState) {
self._name = State(initialValue: tState.name)
}
var body: some View {
...
}
}
struct ContentView: View {
@EnvironmentObject private var tState: TState
var body: some View {
TEditorView(state: tState)
}
}
Or use a @Binding
instead of @State
if the name
value is meant to be two-way.或者,如果
name
值是@State
则使用@Binding
而不是@State
。
In general I'd also question why you need the @EnvironmentObject
in the constructor.一般来说,我还会质疑为什么在构造函数中需要
@EnvironmentObject
。 The idea is with a @EnvironmentObject
is that it's represented the same in all views, so you should only need it body
. @EnvironmentObject
的想法是它在所有视图中表示相同,因此您应该只需要它body
。
If you need any data transformations it should be done in the object model itself, not the view.如果您需要任何数据转换,它应该在对象模型本身中完成,而不是在视图中。
The @State
should be set as private
and per the documentation should only be accessed in the View
body
. @State
应该设置为private
并且根据文档只能在View
body
访问。
https://developer.apple.com/documentation/swiftui/state https://developer.apple.com/documentation/swiftui/state
An @EnvironmentObject
should be set using the ContentView().environmentObject(
YourObservableObject )
一个
@EnvironmentObject
应使用设置ContentView().environmentObject(
YourObservableObject )
https://developer.apple.com/documentation/combine/observableobject https://developer.apple.com/documentation/swiftui/stateobject https://developer.apple.com/documentation/combine/observableobject https://developer.apple.com/documentation/swiftui/stateobject
Below is some Sample code下面是一些示例代码
import SwiftUI
class SampleOO: ObservableObject {
@Published var name: String = "init name"
}
//ParentView
struct OOSample: View {
//The first version of an @EnvironmentObject is an @ObservedObject or @StateObject
//https://developer.apple.com/tutorials/swiftui/handling-user-input
@ObservedObject var sampleOO: SampleOO = SampleOO()
var body: some View {
VStack{
Button("change-name", action: {
self.sampleOO.name = "OOSample"
})
Text("OOSample = " + sampleOO.name)
//Doing this should fix your error code with no other workarounds
ChildEO().environmentObject(sampleOO)
SimpleChild(name: sampleOO.name)
}
}
}
//Can Display and Change name
struct ChildEO: View {
@EnvironmentObject var sampleOO: SampleOO
var body: some View {
VStack{
//Can change name
Button("ChildEO change-name", action: {
self.sampleOO.name = "ChildEO"
})
Text("ChildEO = " + sampleOO.name)
}
}
}
//Can only display name
struct SimpleChild: View {
var name: String
var body: some View {
VStack{
//Cannot change name
Button("SimpleChild - change-name", action: {
print("Can't change name")
//self.name = "SimpleChild"
})
Text("SimpleChild = " + name)
}
}
}
struct OOSample_Previews: PreviewProvider {
static var previews: some View {
OOSample()
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.