Most examples of showing Alert refer to some kind of @State being used as a binding that controls the presented/hidden state of the alert view.
As an example showingAlert (source):
struct ContentView : View {
@State var showingAlert = false
var body: some View {
Button(action: {
self.showingAlert = true
}) {
Text("Show Alert")
}
.alert(isPresented: $showingAlert) {
Alert(
title: Text("Important message"),
message: Text("Wear sunscreen"),
dismissButton: .default(Text("Got it!"))
)
}
}
}
It's a good solution when the alert is triggered from the UI layer - as in the example:
Button(action: {
self.showingAlert = true
}
But what if we want to trigger it from the controller/viewmodel layer with a specific message? As an example, we make a network call - the URLSession’s Publisher can send Data or an Error that we want to push to the user as a message in the Alert.
@State is designed to be managed from the view's body, so it seems that we should rather use an @ObjectBinding in this case. It seems that we also need some message, so we can reference it in the body:
Alert(
title: Text("Important message"),
message: Text(objectBinding.message)
)
The showingAlert would be a bit redundant here as we may define message as String? and create a binding for presentation:
Binding<Bool>(
getValue: { objectBinding.message != nil },
setValue: { if !$0 { objectBinding.message = nil } }
)
It's a doable approach and it works, but two things are making me a bit anxious:
- The fact that
messageis managed by two abstractions - The information and management of the presented/hidden state of the alert leaked into controller/viewmodel/object binding. It'd be nice to keep the presented/hidden state privately in the view.
- The fact that message is kept in the controller/viewmodel/object binding until it gets kind of "consumed" by the view (the binding).
Can it be done better?