Created
February 18, 2021 17:07
-
-
Save schwa/48e4cb47279afa66090d858b1c3e997a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ErrorHandler { | |
var callback: (Error) -> Void | |
func handle(_ block: () throws -> Void) { | |
do { | |
try block() | |
} | |
catch { | |
callback(error) | |
} | |
} | |
} | |
struct ErrorHandlerKey: EnvironmentKey { | |
static var defaultValue = ErrorHandler { | |
fatalError("Unhandled error: \($0)") | |
} | |
} | |
extension EnvironmentValues { | |
var errorHandler: ErrorHandler { | |
get { | |
self[ErrorHandlerKey.self] | |
} | |
set { | |
self[ErrorHandlerKey.self] = newValue | |
} | |
} | |
} | |
struct ErrorHandlingView <Content>: View where Content: View { | |
let content: () -> Content | |
@State | |
var error: Error? | |
@State | |
var isPresented: Bool = false | |
var body: some View { | |
content().environment(\.errorHandler, ErrorHandler() { | |
self.error = $0 | |
self.isPresented = true | |
}) | |
.alert(isPresented: $isPresented, content: { | |
guard let error = error else { | |
fatalError("Ironically our error handler had an error.") | |
} | |
return Alert(title: Text("Error"), message: Text("\(String(describing: error))"), dismissButton: .default(Text("That sucks"))) | |
}) | |
} | |
} | |
////// | |
struct ContentView: View { | |
var body: some View { | |
ErrorHandlingView() { | |
PretendThisViewIsDeeplyBuriedInApp() | |
} | |
} | |
} | |
struct PretendThisViewIsDeeplyBuriedInApp: View { | |
@Environment(\.errorHandler) | |
var errorHandler | |
var body: some View { | |
Button("Crash") { | |
errorHandler.handle { | |
throw MyError() | |
} | |
} | |
} | |
} | |
For bonus points look to get rid of ErrorHandler and just have the environment value be a closure that takes a throwing closure… This would give you:
struct PretendThisViewIsDeeplyBuriedInApp: View {
@Environment(\.errorHandler)
var errorHandler
var body: some View {
Button("Crash") {
errorHandler {
throw MyError()
}
}
}
}```
There is some (minor) value to the explicit ErrorHandler type though (for example a method that just takes an error without having to provide a closure.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This pattern allows you to embed an error handling view anywhere in your view hierarchy.
This view handling view vends an error handler object to all it's children (and their children…)
Errors are caught by the error handler and then displayed by the error handler view.