Best way to enum NSString

Alternative way to use struct:

extern const struct AMPlayerStateReadable
{
    __unsafe_unretained NSString *ready;
    __unsafe_unretained NSString *completed;
    __unsafe_unretained NSString *playing;
    __unsafe_unretained NSString *paused;
    __unsafe_unretained NSString *broken;
} AMPlayerState;

const struct AMPlayerStateReadable AMPlayerState =
{
    .ready = @"READY",
    .completed = @"COMPLETE",
    .playing = @"PLAYING",
    .paused = @"PAUSED",
    .broken = @"BROKEN"
};

Then you can use like this:

NSString *status = AMPlayerState.ready;

Easy to use, readable. Would be nice if someone update/edit answer with advantages/disadvantages of this approach.


Recommended way from apple docs:

You use the NS_TYPED_ENUM to group constants with a raw value type that you specify. Use NS_TYPED_ENUM for sets of constants that can't logically have values added in a Swift extension, and use NS_TYPED_EXTENSIBLE_ENUM for sets of constants that can be expanded in an extension. Apple docs

typedef NSString *MyEnum NS_TYPED_ENUM;
extern MyEnum const MyEnumFirstValue;
extern MyEnum const MyEnumSecondValue;
extern MyEnum const MyEnumThirdValue;

in the .h file. Define your strings in the .m file

MyEnum const MyEnumFirstValue = @"MyEnumFirstValue"
MyEnum const MyEnumSecondValue = @"MyEnumSecondValue";
MyEnum const MyEnumThirdValue = @"MyEnumThirdValue";

Works as expected in both Objective-C

- (void)methodWithMyEnum:(MyEnum)myEnum { }

and Swift

func method(_ myEnum: MyEnum) { }

This will be validated by compiler, so you won't mix up indices accidentally.

NSDictionary *stateStrings =
 @{
   @(MCSessionStateNotConnected) : @"MCSessionStateNotConnected",
   @(MCSessionStateConnecting) : @"MCSessionStateConnecting",
   @(MCSessionStateConnected) : @"MCSessionStateConnected",
  };
NSString *stateString = [stateStrings objectForKey:@(state)];

<nbsp;>

var stateStrings: [MCSessionState: String] = [
    MCSessionState.NotConnected : "MCSessionState.NotConnected",
    MCSessionState.Connecting : "MCSessionState.Connecting",
    MCSessionState.Connected : "MCSessionState.Connected"
]
var stateString = stateStrings[MCSessionState.Connected]

UPDATE: A more Swifty way is to extend the enum with CustomStringConvertible conformance. Also, this way the compiler will safeguard to implement every new addition to the underlying enum (whereas using arrays does not), as switch statements must be exhaustive.

extension MCSessionState: CustomStringConvertible {
    
    public var description: String {
        switch self {
        case .notConnected:
            return "MCSessionState.notConnected"
        case .connecting:
            return "MCSessionState.connecting"
        case .connected:
            return "MCSessionState.connected"
        @unknown default:
            return "Unknown"
        }
    }
}

// You can use it like this.
var stateString = MCSessionState.connected.description

// Or this.
var stateString = "\(MCSessionState.connected)"

OK, I answered myself. Guess I make a mistake.

This is the new feature I mentioned above:

typedef enum Language : NSUInteger{
     ObjectiveC,
     Java, 
     Ruby, 
     Python, 
    Erlang 
}Language;

It's just a new syntax for enum in Xcode 4.4, but I'm so foolish to think we can exchange "NSUInteger" to "NSString".

So here is the way I found that works:

http://longweekendmobile.com/2010/12/01/not-so-nasty-enums-in-objective-c/

// Place this in your .h file, outside the @interface block
typedef enum {
    JPG,
    PNG,
    GIF,
    PVR
} kImageType;
#define kImageTypeArray @"JPEG", @"PNG", @"GIF", @"PowerVR", nil

...

// Place this in the .m file, inside the @implementation block
// A method to convert an enum to string
-(NSString*) imageTypeEnumToString:(kImageType)enumVal
{
    NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
    return [imageTypeArray objectAtIndex:enumVal];
}

// A method to retrieve the int value from the NSArray of NSStrings
-(kImageType) imageTypeStringToEnum:(NSString*)strVal
{
    NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
    NSUInteger n = [imageTypeArray indexOfObject:strVal];
    if(n < 1) n = JPG;
    return (kImageType) n;
}

FYI. The original author of the second example code created a category for enum handling. Just the thing for adding to your very own NSArray class definition.

@interface NSArray (EnumExtensions)

- (NSString*) stringWithEnum: (NSUInteger) enumVal;
- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def;
- (NSUInteger) enumFromString: (NSString*) strVal;

@end

@implementation NSArray (EnumExtensions)

- (NSString*) stringWithEnum: (NSUInteger) enumVal
{
    return [self objectAtIndex:enumVal];
}

- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def
{
    NSUInteger n = [self indexOfObject:strVal];
    if(n == NSNotFound) n = def;
    return n;
}

- (NSUInteger) enumFromString: (NSString*) strVal
{
    return [self enumFromString:strVal default:0];
}

@end

Tags:

Ios

Enums

Xcode