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

时间:2020-08-25 20:02:41

标签: ios swift swiftui

在将类信息从一个结构实例传递到另一个结构实例时,我遇到了麻烦,所以我一直在搞麻烦。

这行得通,因为我正在通过视图

// 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.
            }
}

我收到一个运行时错误,该错误已在函数调用时添加了注释。

对于如何传递引用类型的实例,我感到很困惑,所以我确定我做错了很多事情,我们将不胜感激。

2 个答案:

答案 0 :(得分:2)

这是行不通的,因为EnvironmentObject注入是在SwiftUI View层次结构上仅对所有基于视图的子对象执行的。

如果您希望任何旧对象访问共享实例,则必须手动创建一个单例并将其注入到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)
    }
}

答案 1 :(得分:0)

@ObservedObject var myObservedObject = MyObservedObject()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(myObservedObject)
        }
    }

这足以让您在ContentView的任何其他子视图中获得与myObservedObject相同的environmentObject实例。唯一的例外是.sheet,您需要通过为.environmentObject(envObjInstance)内部的视图使用相同的sheet来为每个图纸手动将environemntObject传递给它们。

对于不符合该视图的结构,您可以只传递环境对象实例的包装值,并且对该传递实例的任何更改也将反映在您的视图中。

方法:

为您的结构声明一个变量:

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%有效,但是我不确定是否可以更简单。您甚至可能不需要将环境对象的包装值传递给该结构,就可以只传递简单值。