简体   繁体   English

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

[英]Can @EnvironmentObject be used with a plain struct that isn't a View?

I'm having troubles with passing class information from one struct instance to another, so I've been messing trying things out.我在将类信息从一个结构实例传递到另一个实例时遇到了麻烦,所以我一直在尝试解决问题。

This works because I'm passing through Views这是有效的,因为我正在通过视图

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

but if I try something similar with just a plain struct that doesn't conform to View like this但如果我尝试类似的东西,只是一个不符合 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.
            }
}

I get a runtime error thats I've put commented in at the calling of the function.我收到一个运行时错误,这是我在函数调用时注释的。

I'm quite confused as to how to pass around an instance of a reference type, so I'm sure I'm doing many things wrong, and any help would be appreciated.我对如何传递引用类型的实例感到非常困惑,所以我确定我做错了很多事情,任何帮助将不胜感激。

That's not going to work because the EnvironmentObject injection is performed on a SwiftUI View hierarchy to all children view-based objects only.这是行不通的,因为EnvironmentObject注入仅在 SwiftUI View层次结构上执行到所有基于子视图的对象。

If you want any old object to access a shared instance, you'll have to create a singleton manually and inject that into the SwiftUI view hierarchy.如果您希望任何旧对象访问共享实例,则必须手动创建一个单例并将其注入 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)
        }
    }

this is enough for you to be able to get the same myObservedObject instance in any other sub view of ContentView as an environmentObject .这足以让您在 ContentView 的任何其他子视图中获得相同的myObservedObject实例作为environmentObject the only exceptions are .sheet s which you'll need to pass the environemntObject to them manually for each sheet by using the same .environmentObject(envObjInstance) modifier for views inside the sheet .唯一的例外是.sheet ,您需要通过使用相同的.environmentObject(envObjInstance)修饰符为sheet内的视图手动为每个 sheet .environmentObject(envObjInstance)修饰符。

for struct not conforming to the view, you can just pass the wrapped value of the instance of your environment object them and any changes to this passed instance will be reflected in your views too.对于不符合视图的结构,您可以将环境对象实例的包装值传递给它们,对此传递的实例的任何更改也将反映在您的视图中。

HOW:如何:

declare a variable for your struct :为您的结构声明一个变量:

struct AnyStruct {

var anEnvironmentObject: EnvironmentObject<TheEnvironmentObjectType>.Wrapper

.
.
.
}

then in a SwiftUI view, first initialize your struct:然后在 SwiftUI 视图中,首先初始化您的结构:

struct someSwiftUIView: View {

@EnvironmentObject var myEnvObj: TheEnvironmentObjectType

var anyStruct: AnyStruct { AnyStruct.init(anEnvironmentObject: $myEnvObject) } 
// notice the dollar sign `$`

}

then in your AnyStruct , you can change the values in the environmentObject and be sure that they will be reflected in your views too.然后在您的AnyStruct ,您可以更改 environmentObject 中的值,并确保它们也将反映在您的视图中。 you just need to remember that you need to use .wrappedValue to assign a new value to a variable that is inside your environment object.您只需要记住,您需要使用.wrappedValue为环境对象内的变量分配一个新值。 assuming your environmentObject has a variable in it named observedInteger :假设您的 environmentObject 中有一个名为observedInteger的变量:

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

note this approach has 100% worked for me, but i'm not sure if can be simpler or not.请注意,这种方法 100% 对我有用,但我不确定是否可以更简单。 you might even not need to pass the wrapped value of your environment object to the struct, you might be able to just passed the simple value.您甚至可能不需要将环境对象的包装值传递给结构体,您可以只传递简单值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法使用 @EnvironmentObject SwiftUI 更新先前视图上的文本 - Can't Update Text on Previous View using @EnvironmentObject SwiftUI 如何在可以生成视图但不是视图的结构中使用@State 和@Environment 属性? - How to use @State and @Environment properties in a struct that can produce a view but isn't a view? 在 SwiftUI 中,我可以在不在 SceneDelegate 中传递 @EnvironmentObject 吗? 喜欢在任何视图中传递它 - In SwiftUI, can I pass @EnvironmentObject not in the SceneDelegate? Like pass it in any View 为什么iOS 5.0不像普通窗口应用程序? 为什么要求使用视图控制器? - Why doesn’t iOS 5.0 like plain window applications? Why does it request that view controllers be used? SwiftUI 视图未更新为 EnvironmentObject 更改 - SwiftUI view is not updating to EnvironmentObject change SwiftUI EnvironmentObject 与 View 不同步 - SwiftUI EnvironmentObject out of sync with View 未使用NSBluetoothPeripheralUsageDescription - NSBluetoothPeripheralUsageDescription isn't being used 为什么我的 SwiftUI 结构不能在视图外初始化? - why can't my SwiftUI struct be initialised outside the View? 将 .environmentObject 与作为工作表呈现的视图一起使用会导致 onReceive 不与 @EnvironmentObject 触发/冲突 - Using .environmentObject with a View presented as a sheet causes onReceive not to fire/conflicts with @EnvironmentObject 在 SwiftUI 中通过摇动手势(使用 UIKit)设置 EnvironmentObject 不会更新视图 - Setting EnvironmentObject from a Shake Gesture (using UIKit) in SwiftUI doesn't update View
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM