Recipe: NSString from an Enum

I had previously outlined a way to get strings from enums and enums from strings. It is posted HERE.

This approach is ok, but I find that it’s not often you need to go from string back to enum. Work with enums and use an enum to string method when you need readability.

Furthermore, it uses an array to do lookups. This doesn’t work so well if your enum values aren’t sequential.

Custom NSError classes come to mind, when you have error codes, but printing an error code to the console is of very little help.

As a result, I did the following for you to consider:

// SOError.h
// A dummy error class

typedef NS_ENUM(NSInteger, SOErrorCode)
{
  SOErrorCodeCocoaError = -1,
  SOErrorCodeUnspecified = 0,
  SOErrorCodeNotConnected = 10,
  SOErrorCodeY2KBug = 99
};

// THIS IS THE METHOD WE CARE ABOUT RIGHT NOW
extern NSString* NSStringFromSOErrorCode(SOErrorCode code);  
extern NSString * const SOErrorDomain;

@interface SOError : NSError

+ (SOError*)errorWithErrorCode:(SOErrorCode)code;  // convenience method.  Sets domain

@end

and now part of the .m file:

#import "SOError.h"
#import "SOError+ErrorCodeConversion.h"  // see next code block!

static NSDictionary *CodeConverter = nil;  

NSString* NSStringFromSOErrorCode(SOErrorCode code)
{
    if (!CodeConverter) {

        // we implement this in a category to reduce boring code in this .m file.
        CodeConverter = [SOError errorCodeConversionDictionary];  
    }
    
    NSString *result = CodeConverter[@(code)];
    
    if (!result) {
        result = @"No description found.  Did you add a new error code but not add it to errorCodeConversionDictionary?";
    }
    
    return result;
}

@implementation SOErrorCode

// Omitted...

@end

What we did above is a lazy load of an NSDictionary that will serve the SOError class. You can just store strings against the error code then look them up when you need them. Then we implement a category on SOError (don’t have to but I like separation of concerns…) and import that.

Then we just implement that category method (not forgetting to declare that in the category header (not shown):

#import "SOError+ErrorCodeDictionary.h"

@implementation SOError (ErrorCodeDictionary)

+ (NSDictionary*)errorCodeConversionDictionary
{
     NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

     // now just use the code as a key, and a string of that enum as a value:
     dictionary[@(SOErrorCodeCocoaError)] = @"SOErrorCodeCocoaError";
     dictionary[@(SOErrorCodeUnspecified)] = @"SOErrorCodeUnspecified";
     dictionary[@(SOErrorCodeNotConnected)] = @"SOErrorCodeNotConnected";
     dictionary[@(SOErrorCodeY2KBug)] = @"SOErrorCodeY2KBug";

     return dictionary.copy;  // immutable
}

And there you go. Strings from Error codes. It’s a bit of work, but if you google around, it would seem there’s no simple way around that boring work.

Advertisements