What is the best practice to share variables between views? My app has only one view. But as it gets more and more complicated, I think I should separate it into several views. Also to separate the methods. I started with something like this:
struct ContentView: View {
@State var str: String = "String"
var body: some View {
VStack(alignment: .leading) {
Text(str)
TextField("Input", text: $str)
Button("button", action: { doSomething() })
}.padding()
}
func doSomething() {
str = str + " " + str
}
}
And want to go there:
class GlobalVars: ObservableObject {
@Published var str: String = "Initial String"
}
struct ContentView: View {
@ObservedObject var globalvars = GlobalVars()
var body: some View {
VStack(alignment: .leading) {
DisplayView()
EditView()
ControlView()
}.padding()
}
}
struct DisplayView: View {
@Binding var str: String
var body: some View {
Text(self.globalvars.str)
}
}
struct EditView: View {
@Binding var str: String
var body: some View {
TextField("Input", text: self.$str)
}
}
struct ControlView: View {
@Binding var str: String
var body: some View {
Button("button", action: { doSomething() })
}
}
func doSomething() {
@Binding var str: String
self.str = self.str + " " + self.str
}
I tried with @Published, @ObservedObject and @Binding. But don't get it. Thank you for any pointer in advance.
There are a number of ways to approach this.
My choice would probably be passing the binding just to the variable that you need access to. That might look like this:
Note that now in
ContentView, there's a parameter passed to each of the subviews, containing a binding (using the$sign) to theGlobalVarsstrproperty.Also,
doSomethinggot moved into the body ofControlViewYou could also use EnvironmentObject to handle this. I'm personally not as big of a fan of this approach because I'd rather see explicitly where my parameters are going. It also gives the subviews access to the entire ObservableObject, which isn't really necessary. But, it shows you the principal:
Note that now,
globalvarsis passed to the children by being placed in the view hierarchy with.environmentObject. Each subview has access to it by declaring a property of@EnvironmentObject var globalvars : GlobalVarsYou could also do kind of a hybrid model where you explicitly pass the ObservableObject as a parameter to the child view: