Elegant way of getting number of items for NS_ENUM

后端 未结 1 734
太阳男子
太阳男子 2020-12-23 17:55

Is there an elegant way of getting the total number of items in a NS_ENUM? And the maximum value?


Some examples:

typedef NS_ENUM(NSInteger, MyE         


        
相关标签:
1条回答
  • 2020-12-23 18:38

    Unfortunately, C enums (which NS_ENUM macro is a generator for) are rather simple, with no reflection.

    If your enum values are consecutive, it's simple to get the number of items using limit values:

    typedef NS_ENUM(NSInteger, MyEnum) {
        MyEnumA = 0,
        MyEnumB,
        MyEnumC,
        MyEnumMax 
    };
    
    NSUInteger numItems = MyNumMax;
    

    However, this is not an ideal solution because when you write a switch, you will get a warning if you don't add a case MyEnumMax: (or default:).

    Your best option then is to create info functions for every enum:

    typedef NS_ENUM(NSInteger, MyEnum) {
        MyEnumA = 0,
        MyEnumB = 2,
        MyEnumC = 4,
    };
    
    NSUInteger MyEnumSize() {
       return 3;
    }
    

    You could also use some advanced macro techniques like X-macros to generate this function dynamically.

    Big warning: X-macros are not simple, not easily readable but they are powerful. Example follows:

    MyEnum.h

    #define MY_ENUM_DEFINITIONS \
        NS_ENUM_X_VALUE(MyEnumA, = 0) \
        NS_ENUM_X_VALUE(MyEnumB,) \
        NS_ENUM_X_VALUE(MyEnumC, = 4)
    
    #define NS_ENUM_X_VALUE(__NAME__, __INT_VALUE__) __NAME__ __INT_VALUE__,
    
    typedef NS_ENUM(NSInteger, MyEnum) {
        MY_ENUM_DEFINITIONS
    };
    
    #undef NS_ENUM_X_VALUE
    
    NSString * NSStringFromMyEnum(MyEnum value);
    NSArray * MyEnumValues();
    NSUInteger MyEnumSize();
    NSUInteger MyEnumMin();
    NSUInteger MyEnumMax();
    

    MyEnum.m

    #define NS_ENUM_X_VALUE(__NAME__, __INT_VALUE__) [__NAME__] = @#__NAME__,
    
    static NSString* MyEnumStringTable[] = {
        MY_ENUM_DEFINITIONS
    };
    
    #undef NS_ENUM_X_VALUE
    
    NSString * NSStringFromMyEnum(MyEnum value) {
        return MyEnumStringTable[value];
    }
    
    #define NS_ENUM_X_VALUE(__NAME__, __INT_VALUE__) @(__NAME__),
    
    static NSOrderedSet * MyEnumValueSet() {
        static NSOrderedSet *valueSet = nil;
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
            valueSet = [[NSOrderedSet alloc] initWithObjects:
            MY_ENUM_DEFINITIONS
            nil];
        });
    
        return valueSet;
    }
    
    #undef NS_ENUM_X_VALUE
    
    
    NSArray *MyEnumValues() {
        return [MyEnumValueSet() array];
    }
    
    NSUInteger MyEnumSize() {
        return MyEnumValueSet().count;
    }
    
    NSUInteger MyEnumMin() {
        return [MyEnumValueSet().firstObject unsignedIntegerValue];
    }
    
    NSUInteger MyEnumMax() {
        return [MyEnumValueSet().lastObject unsignedIntegerValue];
    }
    

    Usage

    NSLog(@"MyEnum size: %@", @(MyEnumSize()));
    NSLog(@"MyEnum min: %@", @(MyEnumMin()));
    NSLog(@"MyEnum max: %@", @(MyEnumMax()));
    
    NSLog(@"MyEnumC value to string: %@", NSStringFromMyEnum(MyEnumC));
    
    for (NSNumber *value in MyEnumValues()) {
        NSLog(@"Value listing: %@ => %@", NSStringFromMyEnum([value unsignedIntegerValue]), value);
    }
    

    Now you can modify/add/remove values in the header and all your functions will be updated automatically.

    0 讨论(0)
提交回复
热议问题