SwiftUI @EnvironmentObject error: may be missing as an ancestor of this view -- accessing object in the init()
SwiftUI @EnvironmentObject error: may be missing as an ancestor of this view -- accessing object in the init()
以下代码产生运行时错误:@EnvironmentObject 错误:作为此视图的祖先可能缺失。环境中的 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
iOS14
答案是显然不能在 init() 函数中访问环境对象。但是,ObservedObject 可以。所以我将代码更改为此并且它有效。为了简单起见,我将 TState 变成了一个我可以在任何地方访问的单例。在许多情况下,这可能会取代 @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 {
...
}
}
此处的另一种方法可能是在构造函数中注入初始 TState
值,并使用 @EnvironmentObject
完全注入 do-away。然后在父视图中,您可以在创建视图时使用 @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)
}
}
或者如果 name
值是 two-way.
,则使用 @Binding
而不是 @State
一般来说,我还会质疑为什么在构造函数中需要 @EnvironmentObject
。 @EnvironmentObject
的想法是它在所有视图中都表示相同,因此您应该只需要它 body
.
如果您需要任何数据转换,应该在对象模型本身而不是视图中完成。
@State
应设置为 private
并且根据文档只能在 View
body
.
中访问
https://developer.apple.com/documentation/swiftui/state
应使用 ContentView().environmentObject(
YourObservableObject)
设置 @EnvironmentObject
https://developer.apple.com/documentation/combine/observableobject
https://developer.apple.com/documentation/swiftui/stateobject
下面是一些示例代码
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()
}
}
以下代码产生运行时错误:@EnvironmentObject 错误:作为此视图的祖先可能缺失。环境中的 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 iOS14
答案是显然不能在 init() 函数中访问环境对象。但是,ObservedObject 可以。所以我将代码更改为此并且它有效。为了简单起见,我将 TState 变成了一个我可以在任何地方访问的单例。在许多情况下,这可能会取代 @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 {
...
}
}
此处的另一种方法可能是在构造函数中注入初始 TState
值,并使用 @EnvironmentObject
完全注入 do-away。然后在父视图中,您可以在创建视图时使用 @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)
}
}
或者如果 name
值是 two-way.
@Binding
而不是 @State
一般来说,我还会质疑为什么在构造函数中需要 @EnvironmentObject
。 @EnvironmentObject
的想法是它在所有视图中都表示相同,因此您应该只需要它 body
.
如果您需要任何数据转换,应该在对象模型本身而不是视图中完成。
@State
应设置为 private
并且根据文档只能在 View
body
.
https://developer.apple.com/documentation/swiftui/state
应使用 ContentView().environmentObject(
YourObservableObject)
@EnvironmentObject
https://developer.apple.com/documentation/combine/observableobject https://developer.apple.com/documentation/swiftui/stateobject
下面是一些示例代码
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()
}
}