1

在视图之间共享变量的最佳做法是什么?我的应用程序只有一个视图。但是随着它变得越来越复杂,我认为我应该将它分成几个视图。还要分开方法。我从这样的事情开始:

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
    }
}

并想去那里:

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
}

我尝试使用@Published、@ObservedObject 和@Binding。但不明白。感谢您提前提供任何指示。

4

1 回答 1

2

有很多方法可以解决这个问题。

我的选择可能是将绑定仅传递给您需要访问的变量。这可能看起来像这样:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(str: globalvars.str) //don't need a binding here since it doesn't get modified
            EditView(str: $globalvars.str)
            ControlView(str: $globalvars.str)
        }.padding()
    }
}
struct DisplayView: View {
    var str:  String //don't need a binding here since it doesn't get modified
    var body: some View {
        Text(str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: $str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        str = str + " " + str
    }
}

请注意,现在在 中ContentView,有一个参数传递给每个子视图,其中包含$对属性的绑定(使用符号)GlobalVars str

doSomething被搬进了ControlView


您也可以使用 EnvironmentObject 来处理这个问题。我个人不太喜欢这种方法,因为我宁愿明确地看到我的参数的去向。它还使子视图可以访问整个 ObservableObject,这并不是必需的。但是,它向您展示了校长:

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()
        .environmentObject(globalvars)
    }
}
struct DisplayView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}
struct EditView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        TextField("Input", text: $globalvars.str)
    }
}
struct ControlView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        globalvars.str = globalvars.str + " " + globalvars.str
    }
}

请注意,现在,globalvars通过放置在视图层次结构中传递给子级.environmentObject。每个子视图都可以通过声明一个属性来访问它@EnvironmentObject var globalvars : GlobalVars


您还可以做一种混合模型,在其中显式将 ObservableObject 作为参数传递给子视图:

struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(globalvars: globalvars)
        }.padding()
        .environmentObject(globalvars)
    }
}

struct DisplayView: View {
    @ObservedObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}
于 2021-03-12T07:40:45.387 回答