@EnvironmentObject可以与不是视图的普通结构一起使用吗?



我在将类信息从一个结构实例传递到另一个结构示例时遇到了问题,所以我一直在尝试。

这是因为我正在通过视图

// phone_testingApp.swift
import SwiftUI
@main
struct phone_testingApp: App {

@ObservedObject var myObservedObject = MyObservedObject()

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(myObservedObject)
}
}
}
// ContentView.swift
import SwiftUI
import Combine
struct ContentView: View {

var subtract = MinusToObject()
@EnvironmentObject var myNumber: MyObservedObject

var body: some View {
VStack{
Text("The number is (myNumber.theObservedObjectToPass)")

MinusToObject()
.environmentObject(myNumber)
}
}
}
class MyObservedObject: ObservableObject {
@Published var theObservedObjectToPass = 5
}
struct MinusToObject: View {

@EnvironmentObject var theObservedObject: MyObservedObject

var body: some View {
Text("Minus")
.onTapGesture {
theObservedObject.theObservedObjectToPass -= 1
}
}
}

但是如果我尝试类似的东西,只使用一个不符合View的普通结构,比如这个

import SwiftUI
import Combine
struct ContentView: View {

var subtract = MinusToObject()
@EnvironmentObject var myNumber: MyObservedObject

var body: some View {
VStack{
Text("The number is (myNumber.theObservedObjectToPass)")

Text("Minus")
.onTapGesture {
subtract.subtractIt()
}
}
}
}
class MyObservedObject: ObservableObject {
@Published var theObservedObjectToPass = 5
}
struct MinusToObject {

@EnvironmentObject var theObservedObject: MyObservedObject


func subtractIt() {
theObservedObject.theObservedObjectToPass -= 1 //Thread 1: Fatal error: No ObservableObject of type MyObservedObject found. A View.environmentObject(_:) for MyObservedObject may be missing as an ancestor of this view.
}
}

我得到了一个运行时错误,我在函数调用时对其进行了注释。

我很困惑如何传递引用类型的实例,所以我确信我做错了很多事情,如果有任何帮助,我将不胜感激。

这不会起作用,因为EnvironmentObject注入是在SwiftUIView层次结构上执行的,仅针对所有基于视图的子对象。

如果您希望任何旧对象访问共享实例,则必须手动创建一个singleton,并将其注入SwiftUI视图层次结构。

class MyObservedObject: ObservableObject {
static let shared = MyObservedObject()
private init() { }
@Published var theObservedObjectToPass = 5
}
/// you can use it in a plain object
struct MinusToObject {
func subtractIt() {
MyObservedObject.shared.theObservedObjectToPass -= 1 
}
}
// you can use it in a view
struct ContentView: View {
var body: some View {
SomeOtherView()
.environmentObject(MyObservedObject.shared)
}
}
@ObservedObject var myObservedObject = MyObservedObject()

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(myObservedObject)
}
}

这足以使您能够在ContentView的任何其他子视图中获得与environmentObject相同的myObservedObject实例。唯一的例外是.sheet,您需要为每张图纸手动将environmentObject传递给它们,方法是对sheet内部的视图使用相同的.environmentObject(envObjInstance)修饰符。

对于不符合视图的struct,您只需将环境对象实例的包装值传递给他们,对该传递实例的任何更改也将反映在视图中。

如何:

为结构声明一个变量:

struct AnyStruct {
var anEnvironmentObject: EnvironmentObject<TheEnvironmentObjectType>.Wrapper
.
.
.
}

然后在SwiftUI视图中,首先初始化您的结构:

struct someSwiftUIView: View {
@EnvironmentObject var myEnvObj: TheEnvironmentObjectType
var anyStruct: AnyStruct { AnyStruct.init(anEnvironmentObject: $myEnvObject) } 
// notice the dollar sign `$`
}

然后在AnyStruct中,您可以更改environmentObject中的值,并确保它们也会反映在您的视图中。您只需要记住,您需要使用.wrappedValue为环境对象内的变量分配一个新值。假设您的environmentObject中有一个名为observedInteger:的变量

extension AnyStruct {
func changeValueOfObservedIntegerToZero() {
self.anEnvironmentObject.observedInteger.wrappedValue = 0
// notice the `.wrappedValue`
}
}

注意,这种方法对我来说100%有效,但我不确定是否可以更简单。您甚至可能不需要将环境对象的包装值传递给结构,您可以只传递简单的值。

最新更新