7
\$\begingroup\$

I have this universal error handler for my HomeKit app (currently in development). It grew out of wanting a single place to write error messages, show alerts, etc. I wanted a short, simple way to call it from anywhere that may generate an error.

Here's the class:

import UIKit
import HomeKit
class ESErrorHandler : NSObject
{
 class func handleError(error: NSError) -> Bool
 {
 NSLog("Handling error \(error) in centralized handler")
 let code = HMErrorCode(rawValue: error.code)
 switch code! {
 case HMErrorCode.FireDateInPast:
 showAlertWithTitle("Invalid date", body: "Date must be in the future")
 case HMErrorCode.AccessDenied:
 showAlertWithTitle("Access Denied", body: "You don't have permission to access the specified item")
 ... // A bunch more cases
 default:
 NSLog("Couldn't handle error with code \(error.code)")
 showAlertWithTitle("Error", body: "Couldn't successfully complete action")
 return false
 }
 return true
 }
 class func showAlertWithTitle(title: NSString, body: NSString)
 {
 dispatch_async(dispatch_get_main_queue())
 {
 let alert = UIAlertView(title: title, message: body, delegate: nil, cancelButtonTitle: "OK")
 alert.show()
 }
 }
}

I call it from other code like this:

homeManager.addHomeWithName(currentHouseName) {(home: HMHome!, error: NSError!) in
 if error != nil
 {
 ESErrorHandler.handleError(error)
 self.title = "Add Home"
 }
 else
 {
 ... //Stuff worked, do other stuff
 }
 }

My concerns:

  • Something feels wrong about putting using a class method for showAlertWithTitle:body:
  • I don't really like having using switch code!, it seems clumsy like I'm missing something in unwrapping
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 25, 2014 at 18:55
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

I don't really like having using switch code!, it seems clumsy like I'm missing something in unwrapping.

Yes, that will crash if the function is called with an error code that does not correspond to one of the HMErrorCode enumeration values. Better use optional binding with if let ...:

class func handleError(error: NSError) -> Bool
{
 if let code = HMErrorCode(rawValue: error.code) {
 switch code {
 case HMErrorCode.FireDateInPast:
 showAlertWithTitle("Invalid date", body: "Date must be in the future")
 case HMErrorCode.AccessDenied:
 showAlertWithTitle("Access Denied", body: "You don't have permission to access the specified item")
 // Other cases ...
 default:
 NSLog("Couldn't handle error with code \(error.code)")
 showAlertWithTitle("Error", body: "Couldn't successfully complete action")
 return false
 }
 } else {
 NSLog("Unknown error with code \(error.code)")
 showAlertWithTitle("Error", body: "Unknown error \(error.code)")
 return false
 }
 return true
}

It is also not obvious from your code why the function has a (boolean) return value, as the caller ignores it.

answered Oct 25, 2014 at 19:48
\$\endgroup\$
1
  • \$\begingroup\$ The boolean return value is so that other code could tell if the error was successfully handled. Thanks! \$\endgroup\$ Commented Oct 25, 2014 at 20:13
1
\$\begingroup\$

Perhaps a cleaner implementation could work as follows.

  1. Create individual error notification types as strings, ie:

    let HMErrorAccessDenied = "HMErrorAccessDenied";

  2. Register a common handler for all of your various error notification types in your application delegate.

    NSNotificationCenter.defaultCenter().addObserver(self, selector:"universalErrorHandler:", name:HMErrorAccessDenied, object:nil);

  3. Instead of tightly coupling your methods with an error handler (like your call to ESErrorHandler.handleError(error) in homeManager.addHomeWithName()) you emit error notifications via NSNotificationCenter.postNotification() and let the registered error handler take care of reacting. This leaves your code flexible in that adding additional handlers at a later date is very easy.

  4. Use the localization features of the Apple-provided frameworks in your handler to load error strings and display those in reaction to the error notifications.

This all assumes that the errors you'll be posting notifications about are things that the user needs to be aware of in some way (though a dialog or an update in the user interface). Other error types, such as recoverable errors, should be passed back to the calling code as either return values or inout parameters.

answered Dec 8, 2014 at 21:48
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.