我正在这样使用@EnvironmentObject
:
struct MyView: View {
@EnvironmentObject var object: MyObject
...
}
但是我的代码不需要object
有一个值。
仅将此选项设置为无效(甚至无法编译-Property type 'MyObject?' does not match that of the 'wrappedValue' property of its wrapper type 'EnvironmentObject'
)
您也不能传入默认对象(也可以解决我的问题)-作为属性的初始值或@EnvironmentObject
的参数。 e.i.这些不起作用:
@EnvironmentObject var object: MyObject = MyObject()
@EnvironmentObject(MyObject()) var object: MyObject
我试图将@EnvironmentObject
包装在自己的属性包装器中,但这根本不起作用。
我还尝试了包装对object属性的访问,但是它不会引发可捕获的异常,而是会引发fatalError
。
我有什么想念的,还是我只是在尝试不可能的事情?
答案 0 :(得分:2)
通过遵循 EnvironmentKey
,您基本上可以提供一个默认值,SwiftUI 可以在丢失的情况下安全地回退到该默认值。此外,您还可以利用 EnvironmentValues
通过基于密钥路径的 API 访问对象。
您可以将两者结合使用,如下所示:
public struct ObjectEnvironmentKey: EnvironmentKey {
// this is the default value that SwiftUI will fallback to if you don't pass the object
public static var defaultValue: Object = .init()
}
public extension EnvironmentValues {
// the new key path to access your object (\.object)
var object: Object {
get { self[ObjectEnvironmentKey.self] }
set { self[ObjectEnvironmentKey.self] = newValue }
}
}
public extension View {
// this is just an elegant wrapper to set your object into the environment
func object(_ value: Object) -> some View {
environment(\.object, value)
}
}
现在从视图访问您的新对象:
struct MyView: View {
@Environment(\.object) var object
}
享受吧!
答案 1 :(得分:0)
我知道您告诉过您您无法将对象放入包装器中,但是我认为此解决方案是实现所需目标的好方法。
您唯一要做的就是创建一个包装器,该包装器将是非可选的,但是将包含您的可选对象:
class MyObjectWrapper: ObservableObject {
@Published var object: MyObject?
}
然后,您创建视图并将包装器分配给环境:
let wrapper = MyObjectWrapper()
// You can try to load your object here, and set it to nil if needed.
let view = MyView().environmentObject(wrapper)
在您看来,您现在可以检查对象的存在:
struct MyView: View {
@EnvironmentObject var objectWrapper: MyObjectWrapper
var body: some View {
if objectWrapper.object != nil {
Text("Not nil")
} else {
Text("Nil")
}
}
}
如果任何视图更改objectWrapper.object
,将重新加载该视图。
您可以轻松模拟视图,甚至在几秒钟后触发更改以检查过渡:
struct MyView_Previews: PreviewProvider {
static var previews: some View {
let objectWrapper = MyObjectWrapper()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
objectWrapper.object = MyObject()
}
return MyView().environmentObject(objectWrapper)
}
}