I am writing a SwiftUI based app, and errors can occur anywhere. I've got a function that logs the error.
But it would be nice to be able to call an Alert Msg, no matter where I am, then gracefully exits the app.
Sure I can right the alert into every view, but that seems ridiculously unnecessary.
Am I missing something?
You can add an alert to the highest view in the current view tree hierarchy and pass it on, for example, via Environment.
Briefly, one of the options:
extension EnvironmentValues {
@Entry var alertError: Binding<Error?> = .constant(nil)
}
enum Destination {
case screen2
case screen3
}
struct ContentView: View {
@State private var presentedError: Error? = nil
var body: some View {
NavigationStack {
Screen1()
.navigationDestination(for: Destination.self) { destination in
switch destination {
case .screen2: Screen2()
case .screen3: Screen3()
}
}
}
.environment(\.alertError, $presentedError)
.alert(
"Error!",
isPresented: .constant(presentedError != nil),
presenting: presentedError,
actions: { _ in
Button("Everything is lost :(") {
presentedError = nil
}
},
message: { error in
Text(error.localizedDescription)
}
)
}
}
struct Screen1: View {
@Environment(\.alertError) private var presentedError
var body: some View {
VStack {
Text("Screen1")
NavigationLink("Next", value: Destination.screen2)
.padding()
Button("Trigger Error") {
presentedError.wrappedValue = MyAwesomeError.screen1
}
}
}
}
struct Screen2: View {
@Environment(\.alertError) private var presentedError
var body: some View {
VStack {
Text("Screen2")
NavigationLink("Next", value: Destination.screen3)
Button("Trigger Error") {
presentedError.wrappedValue = MyAwesomeError.screen2
}
}
}
}
struct Screen3: View {
@Environment(\.alertError) private var presentedError
var body: some View {
VStack {
Text("Screen3")
Button("Trigger Error") {
presentedError.wrappedValue = MyAwesomeError.screen3
}
}
}
}
enum MyAwesomeError: Error, LocalizedError {
case screen1
case screen2
case screen3
var errorDescription: String? { String(describing: self) }
}