Question

In Cocoa and Objective C the favorite method for managing error seems to be using an NSError * object, to construct an error object however, we need to call the following method

+ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict

My question is, what are some of the best practices for managing error domain, error code definitions and user info dictionary across the entire application so that error code, domain and user info dict always stays consistent?

Was it helpful?

Solution

If you have a hefty amount of error construction, your life could be much simpler by using a class. I actually use C++ for this so the calls a program does not need may be removed (unlike objc), but you can use C, ObjC, or C++ for this:

MONErrorDomain.h

// you won't normally need an instance here
@interface MONErrorDomain : NSObject

+ (NSString *)domain; // << required override
- (NSString *)domain; // << returns [[self class] domain]

// example convenience methods:
// uses [self domain]
+ (NSError *)errorWithErrorCode:(NSInteger)errorCode; // << user info would be nil
+ (NSError *)errorWithErrorCode:(NSInteger)errorCode userInfo:(NSDictionary *)userInfo;

@end

MONKoalaError.h

@interface MONKoalaError : MONErrorDomain

+ (NSError *)outOfEucalyptus;

@end

extern NSString * const MONKoalaErrorDomain;

typedef enum MONKoalaErrorCode {
  MONKoalaErrorCode_Undefined = 0,
  MONKoalaErrorCode_OutOfEucalyptus
} MONKoalaErrorCode;

MONKoalaError.m

// apple recommends we use reverse domains
NSString * const MONKoalaErrorDomain = @"com.mon.koala-library.MONKoalaErrorDomain";

@implementation MONKoalaError

+ (NSString *)domain
{
  return MONKoalaErrorDomain;
}

+ (NSError *)outOfEucalyptus
{
  NSDictionary * info = …;
  return [self errorWithErrorCode:MONKoalaErrorCode_OutOfEucalyptus userInfo:info];
}

@end

Then the error creation is all in one place for each domain, and the clients can easily pick their errors without actually building them manually:

if (outError) {
  *outError = [MONKoalaError outOfEucalyptus];
}

and error handling takes the form:

if ([e.domain isEqualToString:MONKoalaErrorDomain]) {
  switch (e.code) {
    case MONKoalaErrorCode_OutOfEucalyptus : {
      self.needsEucalyptus = true;
…

OTHER TIPS

One common way is to define some appropriate constants in a header file, and then include that header file wherever needed. It's a pretty simple approach, and looks like:

const NSString * kMyAppErrorDomain = @"com.example.myapp";
const NSInteger kMyAppSomeError = 2;

// key into user info dictionary
const NSString * kMyAppProblemKey = @"MyAppProblemKey";

I've also seen some applications which create convenience methods for creating these, either as a category on NSError or as a separate utility class or set of functions. It's also entirely reasonable to subclass NSError, for example to customize the localized description.

If you have not already seen it, Apple has released the Error Handling Programming Guide which discusses how these should be used in Cocoa.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top