[iOS-Objective-C] 枚举

参考资料

《编写高质量iOS与OS X代码的52个有效方法》中第5条:用枚举表示状态、选项、状态码

枚举类型的基本使用

枚举的作用在于规范并语义化的定义代码中的状态、选项等常量。枚举类型的定义以关键字enum开头,之后是枚举数据类型的名称,最后是在一对花括号内的选项标识符序列。 编译器会为枚举分配一个独有的编号,从0开始,每个枚举递增1。

enum  Direction {up, down, left, right};

实现枚举所用的数据类型取决于编译器。除了使用默认类型,还可以指明用何种“底层数据类型”来保存枚举类型的变量。

enum Direction : UNSInteger {up, down, left, right};

还可以不使用编译器所分配的序号,而是手工指定某个枚举成员所对应的值。如下例中将 up 的值设为1,而不使用编译器所分配的0。接下来的枚举值会在上一个的基础上递增1。

enum Direction {up = 1, down, left, right};

枚举的另一种使用方式是定义为按位掩码,当定义选项的时候,若这些选项可以彼此组合,则在设置特定的枚举值后,各选项间就可通过“按位或”来组合。因为每个枚举值所对应的二进制表示中,只有1个二进制位的值是1,所以多个选项“按位或”后的组合值是唯一的,且将某一选项与组合值做“按位与”操作,即可判断出组合值中是否包含该选项。

enum Direction {
   up = 1 << 0, 
   down = 1 << 1, 
   left = 1 << 2, 
   right = 1 << 3
};

使用关键字 typedef 重新定义枚举

然而声明或定义一个枚举类型变量的方式却不太简洁,仍然需要使用enum关键字,如:

enum  Direction {up, down, left, right};
enum Direction var1;

enum {up, down, left, right} var1;

为了简化枚举的声明,不需要每次都写enum,可以使用关键字typedef重新定义枚举类型

enum {up, down, left, right} Direction;
typedef enum Direction Direction;

之后就可以直接用 Direction 来代替完整的 enum Direction 了:

Direction var1, var2;

使用枚举的正确姿势

苹果对 Objective-C 语言支持了两个有关枚举的辅助弘,分别是NS_ENUMNS_OPTIONSNS_ENUM用来定义普通的枚举类型,NS_OPTIONS用来定义可组合选项的枚举类型。

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
      UIViewAutoresizingNone = 0,
      UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
      UIViewAutoresizingFlexibleWidth = 1 << 1,
      UIViewAutoresizingFlexibleRightMargin = 1 << 2,
      UIViewAutoresizingFlexibleTopMargin = 1 << 3,
      UIViewAutoresizingFlexibleHeight = 1 << 4,
      UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

这些宏是用#define预处理指令来定义的,具备向后兼容能力,如果目标平台的编译器支持新标准,那就使用新式语法,否则改用旧式语法。具体的定义如下:

#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
  #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
  #if (__cplusplus)
    #define NS_OPTIONS(_type, _name) _type _name; enum : _type
  #else
    #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
  #endif
#else
  #define NS_ENUM(_type, _name) _type _name; enum
  #define NS_OPTIONS(_type, _name) _type _name; enum
#endif

上述代码首先判断编译器是否支持新式枚举,如果不支持,那么NS_ENUMNS_OPTIONS都使用相同的老式语法来定义枚举:

typedef NSInteger Direction;
enum {up, down, left, right};

但是,旧式的语法无法告诉编译器重新定义的枚举类型与之后 enum 定义的整形值之间的联系。如果支持新特性,那么NS_ENUM宏所定义的枚举类型展开之后就是:

typedef enum UITableViewCellStyle : NSInteger UITableViewCellStyle;
enum UITableViewCellStyle : NSInteger {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

根据是否要将代码按 C++ 编译,NS_OPTIONS宏的定义方式也有所不同。如果不按 C++ 编译,那么其展开方式就和NS_ENUM相同。若按 C++ 编译,则展开后的代码略有不同。原因在于,用按位或运算来操作两个枚举值时, C++ 编译模式的处理与非 C++ 模式不一样。在用或运算操作两个枚举值时, C++ 认为运算结果的数据类型应该是枚举的底层数据类型,而 C++ 不允许将这个底层类型“隐式转换”为枚举类型本身。如果想编译通过,就要将按位或操作的结果“显式转换”为枚举类型。所以,在 C++ 模式下应该用另一种方式定义NS_OPTIONS宏,以便省去类型转换操作。

鉴于此,凡是需要以按位或操作来组合的枚举都应使用NS_OPTIONS定义。若是枚举不需要互相组合,则应使用NS_ENUM来定义。

枚举在 switch 语句中的应用

当在 switch 语句中使用 enum 值时,不建议添加 default 分支。因为 enum 的选项分支已经包含了所有可能的情况,并不需要额外处理默认情况。而且,当之后添加新的状态时,编译器还会发出警告信息,提示新加入的状态并未在 switch 分支中处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容