I'm using @EnvironmentObject
like this:
struct MyView: View {
@EnvironmentObject var object: MyObject
...
}
but my code doesn't need there to be a value for object
.
Just making this optional doesn't work (doesn't even compile - Property type 'MyObject?' does not match that of the 'wrappedValue' property of its wrapper type 'EnvironmentObject'
)
You also can't pass in a default object (that would solve my problem too) - either as an initial value to the property, or as a parameter to @EnvironmentObject
. e.i. these don't work:
@EnvironmentObject var object: MyObject = MyObject()
@EnvironmentObject(MyObject()) var object: MyObject
I've tried to wrap the @EnvironmentObject
in my own property wrapper, but that just doesn't work at all.
I've also tried wrapping accesses to the object property, but it doesn't throw an exception which can be caught, it throws a fatalError
.
Is there anything I'm missing, or am I just trying the impossible?
It's not a very elegant and could easily break if anything in EnvironmentObject changes (and other caveats), but if you print EnvironmentObject in SwiftUI 1 / Xcode 11.3.1 you get:
EnvironmentObject<X>(_store: nil, _seed: 1)
so how about:
extension EnvironmentObject {
var hasValue: Bool {
!String(describing: self).contains("_store: nil")
}
}
By conforming to EnvironmentKey
you basically can provide a default value that SwiftUI can safely fallback to in case of missing. Additionally, you can also leverage EnvironmentValues
to access the object via key path based API.
You can combine both with something like this:
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)
}
}
Now to access your new object from a view:
struct MyView: View {
@Environment(\.object) var object
}
Enjoy!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With