本文介绍 C 与 Objective-C 中的枚举,同时对 Objective-C 中的字符串枚举进行介绍

C语言中的枚举

C语言中也是有枚举的,或者说枚举正是从C语言中诞生的。在C语言中,枚举使用 enum 关键字声明,辅以 typedef。让我们来举个例子:

typedef enum RKOEnumType {
    RKOEnumTypeNone = 0,
    RKOEnumTypeNormal,
    ...
} RKOEnumType;

上面的代码便定义了一个枚举类型 RKOEnumType,使用它声明变量时我们可以这么使用:

RKOEnumType type = RKOEnumTypeNone;

而用它进行判断时则是这样的:

switch (type) {
    case RKOEnumTypeNone:
        // some code
        break;
    case RKOEnumTypeNormal:
        // some code
        break;
        ...
}

Objective-C 中的枚举

Objective-C 语言中,Foundaation 框架为我们封装了一套更方便的枚举定义方法。那便是 NS_ENUMNS_OPTIONS

NS_ENUM

NS_ENUM 用来申明单选类型的枚举,即枚举变量中只可以有一种值。让我们来看一下栗子:

typedef NS_ENUM(NSInteger, RKOEnumType) {
    RKOEnumTypeNone = 0,
    RKOEnumTypeNormal,
    ...
};

我们可以看到,这里用 NSInteger 声明了枚举变量的类型,即整数类型,其在使用时和 C语言 并无区别,依然使用 switch 语法用以区分每种不同的枚举变量。

NS_OPTIONS

除了 NS_ENUM 之后,Objective-C 还为我们封装了一套 NS_OPTIONS。有的时候单一的枚举值并不满足我们的需求,例如在如下场景时:我们希望设一个视图的可选转方向,它即可向左旋转,又可向右旋转。这时如果我们使用枚举来代表旋转方向的话,显然我们不应该设置一个枚举值为“既可向左又可向右”,我们依然定义一个 RKORotatTypeLeft 一个 RKORotatTypeRight,然后多选它们。那么我们该如何定义呢?下面来举个例子:

typedef NS_OPTIONS(NSUInteger, RKORotatType) {
    RKORotatTypeRightNone = 0,  // 2进制中的 0000
    RKORotatTypeRight = 1 << 0,  // 值为2的0次方,二进制中的 0001
    RKORotatTypeLeft = 1 << 1,  // 值为2的1次方,二进制中的 0010
    ...
};

这样我们使用 NS_OPTIONS,结合位移操作,就定义了一个可以进行多选的枚举类型了。需要注意的是,NS_OPTIONS 使用的变量类型为 NSUInteger。而不是 NS_ENUMNSInteger

在对变量赋值时,我们使用 | 或运算符连接多个不同的枚举值,例如:

RKORotatType type = RKORotatTypeRight | RKORotatTypeLeft;

判断

NS_OPTIONS 在对变量的判断上与 NS_ENUM 不同,因为变量中可以包含多个值,所以我们就不方便使用 switch 来进行判断了。

一般的,我们使用 if 来进行 NS_OPTIONS 类型的枚举的值判读,如下所示:

// RKORotatTypeRight
if (type & RKORotatTypeRight) {
    // some code
}

// 包含 RKORotatTypeLeft
if (type & RKORotatTypeLeft) {
    // some code    
}

使用 if 判断,结合 & 与运算符,我们即可判断变量中是否包含某个具体的枚举值,进而执行操作。

排除

有的时候,我们为了方便,有可能定义下面这样的一个选项枚举:

typedef NS_OPTIONS(NSUInteger, RKORotatType) {
    RKORotatTypeRightNone = 0,
    RKORotatTypeRight = 1 << 0,
    RKORotatTypeLeft = 1 << 1,
    RKORotatTypeTop = 1 << 2,
    RKORotatTypeBottom = 1 << 3,
    
    RKORotatTypeAll = RKORotatTypeRight | RKORotatTypeLeft | RKORotatTypeTop | RKORotatTypeBottom,
};

这里我额外定义了一个枚举选项为 RKORotatTypeAll,代表所有的旋转类型。现在我们有可能有这么一个需求,点击某个按钮,或者执行了某个操作之后,要禁止这个视图向左旋转。

我们可以重新对 type 进行赋值,也可以像下面这样,将 RKORotatTypeLefttype排除掉

type = type & (~RKORotatTypeLeft);

RKORotatTypeLeft 取反后再与 type 进行与操作,即可从 type移除 RKORotatTypeLeft 选项。

C数组与字符串枚举

如上所述,c 与 Objective-C 的常见枚举都是 int 类型,如果我们需要一个字符串枚举呢?

我们可以借助 c 数组来实现。首先定义一个常见的 Objective-C 枚举:

typedef NS_ENUM(NSUInteger, KLType) {
    KLTypeRed = 1,
    KLTypeGreen = 2,
    KLTypeOrange = 3,
};

随后使用该 Objective-C 枚举作为下标,定义 c 数组:

// 这个是 Map NSString * 类型的数组
NSString *KLTypeStringMap[] = {
    [KLTypeRed] = @"红色",
    [KLTypeGreen] = @"绿色",
    [KLTypeOrange] = @"橘色"
};

// 使用:
KLTypeStringMap[KLTypeRed];

参考

  1. iOS Enum-枚举的正确使用——Snow_xueY
  2. NS_OPTIONS枚举的用法——Channe
  3. OC中枚举写法 以及 字符串类型枚举实现探索