Difference between @environment vs @environmentObject in SwiftUI
Both of them @Environment and @EnvironmentObject are property wrappers while @Environment keeps values with predefined keys, @EnvironmentObject keeps not only predefined keys but also arbitrary values. For example if you need to keep information about your User object which includes name, age, gender etc. you need to use @EnvironmentObject, whereas if you would like to keep whether device is in dark or light mode, system local language, calendar preferences, edit mode it is great for using @Environment.
@Environment
is a key/value pair, whereas @EnvironmentObject
is just a value identified by its type. Both are variable storage property wrappers.
@Environment(\.locale) var locale: Locale
@EnvironmentObject var user: User // is an object where you keep user-related information
@EnvironmentObject
- Its similar like
@ObservedObject
- The model should conform to the
ObservableObject
protocol - We need to mark properties in this model as
@Published
to notify changes to view which actively using the object - The model object should be as class for sure
- No need for default value, because it can read default value from environment. If object is not available in environment, app will crash.
- Another major difference is, say we have 5 views(V1…V5), if we want to pass a object directly from V1 to V5 we could use
@EnvironmentObject
rather than@ObservedObject
. Set data to be passed in V1 and retrieve it in V5(or wherever needed). Code will be much simple. - It will hold only one type of instance at same time environment.
- Its purely based on views. If a parent view sets environment object all its child can make use of it. If another parent view set another env object, their child’s can make us of it. Eg: If you set environment object in your ContentView in SceneDelegate all its child views can make use of it.
@Environment
- We can use this to get system-related values like whether apps are running in light or dark mode, core data’s managed object context, size classes, etc…
- We need to provide proper keys to access its value because it holds the same datatype against multiple keys.
@Environment
is value type but@EnvironmentObject
is reference type.You can only use a single instance of objects in
@EnvironmentObject
.If you add another instance of an object, it will replace the previous one.But as,
@Environment
key value pair, just make sure key is different.You just need to use
@EnvironmentObject var object: Object
to make an object retrieve the instance from the environment, and inject the instance by.environmentObject(Object())
On the other hand, there are many predefined
@Environment
system-managed environment values. You can also create custom one. It needs to bestruct
type and conforms toEnvironmentKey
.
Here is an example,
struct SunlightKey: EnvironmentKey {
static var defaultValue: Double = 1.09
}
Then add it to the EnvironmentValues
as an extension of it.
Here is a basic example
extension EnvironmentValues {
var sunlight: Double {
get { self[SunlightKey.self] }
set { self[SunlightKey.self] = newValue }
}
}
Then, use it like, @Environment(\.sunlight) var sunlight
in view file and inject value by .environment(\.sunlight, 4.05)
Hope, this helps