Skip to content

Instantly share code, notes, and snippets.

@orj
Last active October 5, 2016 15:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save orj/582521aaa56d74d60f7b31f774816f9e to your computer and use it in GitHub Desktop.
Save orj/582521aaa56d74d60f7b31f774816f9e to your computer and use it in GitHub Desktop.
A protocol that can be adopted by ErrorType, RawRepresentable conforming types that provides a mechanism for providing NSError userInfo values.
/// A protocol that can be adopted by ErrorType, RawRepresentable conforming types that
/// provides a mechanism for providing NSError userInfo values.
///
/// There are nil returning default implementations of all of the members of this protocol.
protocol NSErrorUserInfoValueProviding {
var localizedDescription: String? { get }
var localizedFailureReason: String? { get }
var localizedRecoverySuggestion: String? { get }
var localizedRecoveryOptions: [String]? { get }
/// The returned object should conform to NSErrorRecoveryAttempting informal protocol.
var recoveryAttempter: AnyObject? { get }
var helpAnchor: String? { get }
}
// Default implementation through protocol extension.
extension NSErrorUserInfoValueProviding {
var localizedDescription: String? {
return nil
}
var localizedFailureReason: String? {
return nil
}
var localizedRecoverySuggestion: String? {
return nil
}
var localizedRecoveryOptions: [String]? {
return nil
}
var recoveryAttempter: AnyObject? {
return nil
}
var helpAnchor: String? {
return nil
}
}
private extension NSErrorUserInfoValueProviding {
func userInfoValue(forKey key: String) -> AnyObject? {
switch key {
case NSLocalizedDescriptionKey: return self.localizedDescription
case NSLocalizedFailureReasonErrorKey: return self.localizedFailureReason
case NSLocalizedRecoverySuggestionErrorKey: return self.localizedRecoverySuggestion
case NSLocalizedRecoveryOptionsErrorKey: return self.localizedRecoveryOptions
case NSRecoveryAttempterErrorKey: return self.recoveryAttempter
case NSHelpAnchorErrorKey: return self.helpAnchor
default: return nil
}
}
}
extension NSError {
/// Register a user info value providing error type.
static func registerUserInfoValueProvidingErrorType<T: protocol<RawRepresentable,
NSErrorUserInfoValueProviding, ErrorType> where T.RawValue == Int>(providerType: T.Type) {
self.setUserInfoValueProviderForDomain(String(reflecting: providerType)) {
(nsError, key) -> AnyObject? in
let error = providerType.init(rawValue: nsError.code)
return error?.userInfoValue(forKey: key)
}
}
}
/// A custom ErrorType that adopts the NSErrorUserInfoValueProviding protocol to
/// provide a failure reason and recovery suggestion.
///
/// It is important that this ErrorType be marked as being exposed to Objective-C
/// via the @objc() attribute so that it is bridged through to NSError fully.
@objc(IBAMyCustomError)
enum MyCustomError : Int, ErrorType, NSErrorUserInfoValueProviding {
case ServersUnreachable = 1000
case EverythingIsFullOfWoe = 1001
var localizedFailureReason: String? {
switch self {
case .ServersUnreachable:
return NSLocalizedString("Servers are unreachable.", comment: "Servers unreachable failure reason.")
case .EverythingIsFullOfWoe:
return NSLocalizedString("Woe woe woe.", comment: "Full of woe error message.")
}
}
var localizedRecoverySuggestion: String? {
switch self {
case .ServersUnreachable:
return NSLocalizedString("Ensure you have Internet connectivity.", comment: "Pipes are clogged.")
case .EverythingIsFullOfWoe:
return NSLocalizedString("😩 😭.", comment: "Cry a bunch.")
}
}
}
// Register the ErrorType with NSError elsewhere in the codebase (eg, in the AppDelegate)
NSError.registerUserInfoValueProvidingErrorType(MyCustomError.self)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment