Forked from nicklockwood/Pattern for Swift Errors.swift
Created
August 18, 2017 18:30
Revisions
-
nicklockwood revised this gist
Aug 16, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -37,7 +37,7 @@ enum ApplicationError: Error, CustomStringConvertible { // Convenience constructor for converting any unknown error to an ApplicationError // this is useful when receiving errors where we're not sure what type they are, // which is more common that not given Swift's lack of Error type annotations init(_ error: Error) { if let error = error as? ApplicationError { self = error -
nicklockwood revised this gist
Aug 16, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -22,7 +22,7 @@ enum ApplicationError: Error, CustomStringConvertible { case let message(message): return message case let generic(error): if let error = error as? CustomStringConvertible { return error.description } // Always returns something, but not always something useful -
nicklockwood revised this gist
Aug 16, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -42,7 +42,7 @@ enum ApplicationError: Error, CustomStringConvertible { if let error = error as? ApplicationError { self = error } else { self = .generic(error) } } -
nicklockwood created this gist
Aug 16, 2017 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,79 @@ // Swift's untyped errors are a goddam PiTA. Here's the pattern I use to try to work around this. // The goal is basically to try to guarantee that every throwing function in the app throws an // ApplicationError instead of some unknown error type. We can't actually enforce this statically // But by following this convention we can simplify error handling enum ApplicationError: Error, CustomStringConvertible { // These are application-specific errors that may need special treatment case specificError1 case specificError2(SomeType) ... // These are generic cases for errors that don't need special treatment case message(String) case generic(Error) // Always handy to be able to print your errors var description: String { switch self { case .specificError1, .specificError2: // Application-specific case let message(message): return message case let generic(error): if let error = error as CustomStringConvertible { return error.description } // Always returns something, but not always something useful return (error as NSError).localizedDescription } } // Convenience constructor to save writing `ApplicationError.message(...)` all the time init(_ message: String) { self = .message(message) } // Convenience constructor for converting any unknown error to an ApplicationError // this is useful when receiving errors where we're not sure what type they are, // which is more common that not gvien Swift's lack of Error type annotations init(_ error: Error) { if let error = error as? ApplicationError { self = error } else { self = .generic(message) } } // By wrapping a call with this function, you can convert any thrown error to an ApplicationError // usage 1: `let result = try ApplicationError.wrap(someFunctionWithNoArguments)` // usage 2: `let result = try ApplicationError.wrap { try someFunction(with: arguments) }` static func wrap<T>(_ closure: () throws -> T) throws -> T { do { return try closure() } catch { throw self.init(error) } } // Like `wrap` above, but instead of calling the function and wrapping the error immediately, // this returns a new function that throws an ApplicationError instead of the original error // usage: let appErrorFn = ApplicationError.wrap(someUntypedErrorFn) static func wrap<T>(_ closure: @escaping () throws -> T) -> () throws -> T { return { try wrap(closure) } } // This function is basically an alternative version of try? that logs (or performs some other // application-specific action) instead of failing silently. This is useful if you need to call // a throwing function inside a function that doesn't throw, such as a delegate method static func attempt<T>(_ closure: () throws -> T) -> T? { do { return try closure() } catch { let error = ApplicationError(error) print(error.description) // Could do something more sophisticated, like store error in a global return nil } } }