【问题标题】:Elegant way of getting number of items for NS_ENUM获取 NS_ENUM 项目数量的优雅方式
【发布时间】:2014-09-01 22:51:06
【问题描述】:

有没有一种优雅的方法来获取 NS_ENUM 中的项目总数?以及最大值?


一些例子:

typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnumA = 0,
    MyEnumB = 1,
    MyEnumC = 2
};
// NumberOfItems(MyEnum) -> 3, MaximumValue(MyEnum) -> 2.


typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnumA,
    MyEnumB,
    MyEnumC
};
// NumberOfItems(MyEnum) -> 3, MaximumValue(MyEnum) -> 2.


typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnumA = 4,
    MyEnumB,
    MyEnumC
};
// NumberOfItems(MyEnum) -> 3, MaximumValue(MyEnum) -> 6.


typedef NS_ENUM(NSInteger, MyEnum)
{
    MyEnumA = 0,
    MyEnumB = 2,
    MyEnumC = 4
};
// NumberOfItems(MyEnum) -> 3, MaximumValue(MyEnum) -> 4.

【问题讨论】:

  • NS_ENUM 实际上只是一个 C 枚举的宏。
  • @Eonil:复制与否,这是值得的。你指出的问题的唯一答案显然不是我想要的。

标签: objective-c c enums


【解决方案1】:

不幸的是,C 枚举(NS_ENUM 宏是其生成器)相当简单,没有反射。

如果您的枚举值是连续的,则使用限制值获取项目数很简单:

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

NSUInteger numItems = MyNumMax;

但是,这不是一个理想的解决方案,因为当您编写 switch 时,如果您不添加 case MyEnumMax:(或 default:),则会收到警告。

那么你最好的选择是为每个枚举创建信息函数:

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

NSUInteger MyEnumSize() {
   return 3;
}

您还可以使用一些高级宏技术,例如X-macros 来动态生成此函数。

大警告:X 宏并不简单,不易阅读,但它们功能强大。示例如下:

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];
}

用法

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);
}

现在您可以修改/添加/删除标题中的值,您的所有功能都将自动更新。

【讨论】:

  • 感谢您的回答!您能否详细说明 X 宏是什么以及如何生成这样的 X 宏?
  • @RicardoSánchez-Sáez 正在努力,稍后会更新,因为这有点复杂。
  • @RicardoSánchez-Sáez 已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 2013-04-01
  • 2022-01-16
  • 2018-11-30
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
相关资源
最近更新 更多