我发现我的应用程序中有几个用于各种目的的警报框。为了追求DRY(不要重复自己)的目标,我想集中这段代码。我天真的方法是编写一个 ViewModel 来控制警报状态,包括内容以及是否显示。代码很简单
@MainActor
class AlertViewModel: ObservableObject {
@Published var showAlert = false
@Published var title: String = "Default Alert title"
@Published var message: String = "Default Alert Message"
}
然后就可以这样使用了
struct MainView: View {
@StateObject var vm = AlertViewModel()
var body: some View {
Button("Show alert on main view") {
vm.showAlert = true
}
.alert(isPresented: $vm.showAlert) {
Alert(title: Text(vm.title), message: Text(vm.message))
}
}
}
而且效果非常好。但是,从子视图使用它不起作用。这是上面的代码与子视图的结合
struct SubView: View {
@StateObject var vm = AlertViewModel()
var body: some View {
Button("Show alert on sub view") {
vm.showAlert = true
}
}
}
struct MainView: View {
@StateObject var vm = AlertViewModel()
var body: some View {
SubView()
Button("Show alert on main view") {
vm.showAlert = true
}
.alert(isPresented: $vm.showAlert) {
Alert(title: Text(vm.title), message: Text(vm.message))
}
}
}
子视图按钮不会导致警报显示。
为什么?
有解决办法吗?
我是否不必要地追求代码极简主义?
这里正确的做法是什么?
首次创建 MainView 时,@StateObject 将实例化 AlertViewModel。 在 SubView 中,您使用了 @StateObject,这将创建 AlertViewModel 的另一个实例。 有两个不同的 AlertViewModel 实例,这就是为什么在子视图中单击按钮时不显示警报的原因。
要使用 MainView 中的相同实例,您应该传递 AlertViewModel
SubView(vm: vm)
在子视图中使用ObservedObject
@ObservedObject var vm: AlertViewModel
如果你想将AlertViewModel传递给随机的子View,而不是像链一样将AlertViewModel传递给所有子View,你可以使用环境对象
struct MainView: View {
@StateObject var vm = AlertViewModel()
var body: some View {
VStack {
SubViewOne()
Button("Show alert on main view") {
vm.showAlert = true
}
.alert(isPresented: $vm.showAlert) {
Alert(title: Text(vm.title), message: Text(vm.message))
}
}
.environmentObject(vm)
}
}
struct SubViewOne: View {
var body: some View {
SubViewTwo()
}
}
struct SubViewTwo: View {
@EnvironmentObject var vm: AlertViewModel
var body: some View {
Button("Show alert on sub view two") {
vm.showAlert = true
}
}
}