[Edit: note that @ObjectBinding is no longer around; instead you can use @State to mark an instance variable as requiring a view refresh when it changes.]
When a view declares an @State
or @Binding
variable, its value must be explicitly passed from the view's parent. So if you have a long hierarchy of views with some piece of data from the top being used in the bottom, you must code every level of that hierarchy to know about and pass down the data.
In his comment at 29:00, he is contrasting this to using @EnvironmentVariable in a child view, which searches the whole hierarchy for that piece of data. This means any views that do not explicitly need the data can effectively ignore it. Registering a variable needs only be done once (via .environmentObject(_)
on a view).
Here is a contrived example. Given some data type conforming to ObservableObject
,
class SampleData: ObservableObject {
@Published var contents: String
init(_ contents: String) {
self.contents = contents
}
}
Consider this view hierarchy:
struct ContentView: View {
@State private var data = SampleData("sample content")
var body: some View {
VStack {
StateViewA(data: self.data)
EnvironmentViewA()
.environmentObject(self.data)
}
}
}
struct StateViewA: View {
@State var data: SampleData
var body: some View {
StateViewB(data: self.data)
}
}
struct StateViewB: View {
@State var data: SampleData
var body: some View {
Text(self.data.contents)
}
}
struct EnvironmentViewA: View {
var body: some View {
EnvironmentViewB()
}
}
struct EnvironmentViewB: View {
@EnvironmentObject var data: SampleData
var body: some View {
Text(self.data.contents)
}
}
The result in ContentView
will be two views that display the same piece of text. In the first, StateViewA
must pass the data on to its child (i.e. the model is passed from "hop to hop"), whereas in the second, EnvironmentViewA
does not have to be aware of the data at all.