子视图无法触发SwiftUI Alert

问题描述 投票:0回答:1

我发现我的应用程序中有几个用于各种目的的警报框。为了追求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))
        }
    }
}

子视图按钮不会导致警报显示。

为什么?

有解决办法吗?

我是否不必要地追求代码极简主义?

这里正确的做法是什么?

ios swift swiftui mvvm alert
1个回答
0
投票

首次创建 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
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.