Enum-枚举的正确使用-Effective-Objective-C-读书笔记

原文 http://tutuge.me/2015/03/21/effective-objective-c-5-enum/?utm_source=tuicool&utm_medium=referral

前言

Enum,也就是枚举,从C语言开始就有了,C++、Java、Objective-C、Swift这些语言,当然都有对应的枚举类型,功能可能有多有少,但是最核心的还是一个—规范的定义代码中的状态、选项等“常量”。

Item 5 - Use Enumerations for States, Options, and Status Codes

本节的内容就是如何正确的使用枚举。

状态与选项的区别(states and options)

在用enum之前,我个人觉得,区分一下状态和选项的概念还是很必要的。

状态,同时只能有一种,如“OK”,“Error”,不可能同时是OK和Error。
选项,同时可以有一种或一种以上,如App可以同时支持横屏和竖屏,横屏竖屏在这个时候就是“屏幕方向”的两种不同的选项。

接下来,我们看看如何用枚举定义状态和选项。

enum与状态(states)

不好的做法

经常看到这样的写法:

1 #define STATE_OK 0
2 #define STATE_ERROR 1
3 #define STATE_UNKNOW 2
4
5 //直接用int型变量接收
6 int STATE = STATE_UNKNOW;

这样做有如下“不恰当”:

  • 宏定义没有类型约束,只是单纯的替换。
  • 无法限制状态的所有情况,如,认为的将STATE赋值成3,程序可能就会出错,找不到匹配的状态,因为编译器不会对“STATE = 3;”提出警告。

正确的做法

1 typedef enum _TTGState {
2     TTGStateOK  = 0,
3     TTGStateError,
4     TTGStateUnknow
5 } TTGState;
6
7 //指明枚举类型
8 TTGState state = TTGStateOK;

用的时候就如下:

 1 - (void)dealWithState:(TTGState)state {
 2     switch (state) {
 3         case TTGStateOK:
 4             //...
 5             break;
 6         case TTGStateError:
 7             //...
 8             break;
 9         case TTGStateUnknow:
10             //...
11             break;
12     }
13 }

enum与选项 (options)

选项,就是说一个“选项变量”的类型要能够同时表示一个或多个组合的选择,如下例子:

1 //方向,可同时支持一个或多个方向
2 typedef enum _TTGDirection {
3     TTGDirectionNone = 0,
4     TTGDirectionTop = 1 << 0,
5     TTGDirectionLeft = 1 << 1,
6     TTGDirectionRight = 1 << 2,
7     TTGDirectionBottom = 1 << 3
8 } TTGDirection;

看,这里的选项是用位运算的方式定义的,这样的好处就是,我们的选项变量可以如下表示:

 1 //用“或”运算同时赋值多个选项
 2 TTGDirection direction = TTGDirectionTop | TTGDirectionLeft | TTGDirectionBottom;
 3
 4 //用“与”运算取出对应位
 5 if (direction & TTGDirectionTop) {
 6     NSLog(@"top");
 7 }
 8 if (direction & TTGDirectionLeft) {
 9     NSLog(@"left");
10 }
11 if (direction & TTGDirectionRight) {
12     NSLog(@"right");
13 }
14 if (direction & TTGDirectionBottom) {
15     NSLog(@"bottom");
16 }

direction变量的实际内存如下:

这样,用位运算,就可以同时支持多个值。

enum在Objective-C中的“升级版”

一般来说,我们不能指定枚举变量的实际类型是什么,就是说,我们不知道枚举最后是int型,还是其他的什么类型。但是从C++ 11开始,我们可以为枚举指定其实际的存储类型,如下语法:

enum TTGState : NSInteger {/*...*/};

但是,我们在定义枚举的时候如何保证兼容性呢?Foundation框架已经为我们提供了更加“统一、便捷”的枚举定义方法,我们重新定义上面的例子:

 1 //NS_ENUM,定义状态等普通枚举
 2 typedef NS_ENUM(NSUInteger, TTGState) {
 3     TTGStateOK = 0,
 4     TTGStateError,
 5     TTGStateUnknow
 6 };
 7
 8 //NS_OPTIONS,定义选项
 9 typedef NS_OPTIONS(NSUInteger, TTGDirection) {
10     TTGDirectionNone = 0,
11     TTGDirectionTop = 1 << 0,
12     TTGDirectionLeft = 1 << 1,
13     TTGDirectionRight = 1 << 2,
14     TTGDirectionBottom = 1 << 3
15 };

所以,在开发Mac、iOS程序中,最好所有的枚举都用“NS_ENUM”和“NS_OPTIONS”定义,保证统一。

总结

充分的用好枚举,可以增强代码的可读性,减少各种“错误”,让代码更加的规范。

时间: 2024-10-23 02:38:06

Enum-枚举的正确使用-Effective-Objective-C-读书笔记的相关文章

[.NET] 《Effective C#》读书笔记(二)- .NET 资源托管

<Effective C#>读书笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内存,我们并不需要去担心内存泄漏,资源分配和指针初始化等问题.不过,它也并非万能,因为非托管资源需要我们自己进行清理,如文件句柄.数据库连接.GDI+ 对象和COM 对象等. 目录 十二.推荐使用成员初始化器而不是赋值语句 十三.正确地初始化静态成员变量 十四.尽量减少重复的初始化逻辑 十五.使用 using

《Effective C++》 读书笔记之四 设计与申明

<Effective C++> 读书笔记之四 设计与申明 条款18:让接口容易被正确使用,不易被误用. 重点: 好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. "促进正确使用"的办法包括接口的一致性,以及与内置类型的行为兼容. "阻止误用"的办法包括建立新类型.限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. tr1::shared_ptr支持定制型删除器.这可防范DLL问题,可被用来自动解除互斥锁等等. 20

《Effective C++》 读书笔记之三 资源管理

<Effective C++> 读书笔记之三 资源管理 准备知识: 所谓资源就是,一旦用了它,将来必须还给系统.最常用的资源是动态分配内存,其他常见的资源有文件描述器.互斥锁.图形界面的字形和笔刷.数据库连接以及网络sockets. auto_ptr 是个"类指针对象",就是所谓的智能指针,其析构函数自动对其所指对象调用delete.auto_ptr位于 #include <memory> 头文件.由于auto_ptr被销毁时会自动删除它所指之物,所以一定要注意

《Effective C++》读书笔记汇总

我之前边读<Effective C++>边写下每个条款的读书笔记,这一版是C++11之前的版本.这里我将每个条款令我印象深刻的点小结一下. 1.C++包括:Plain C(面向过程).OOP(面向对象).模板(泛型和模板元编程).STL(C++标准库). 2.用inline.enum.const代替#define.#define定义的宏,一旦复杂起来,高手都很难掌控.不要带入C的习惯. 3.灵活使用const前缀.不需要进行改变的数据加上const前缀.指针的const前缀有两种形式,cons

《Effective Java》读书笔记

创建和销毁对象 静态工厂模式 构造器里未传参的成员不会被初始化.int类型是0,布尔类型是false,String类型是null,List<>也是null. 重叠构造器 进阶1:javabean模式,使用set方法来初始化成员,缺点是构造过程中javabean可能处于不一致状态(可以理解成该模式下成员的设置的分步进行的,可能某处使用到该类的某个成员时其还未被初始化),并且该模式阻止了把类变成不可能的可能,需要考虑线程安全. 进阶2: Builder模式:类里定义一个静态类builder(其实就

〈Effective C++〉读书笔记--Accustoming Youself to C++

1.View C++ as a federation of languages.把C++看成4种子语言组成,即C.Object-Oriented C++.Template C++.The STL. 2.Things to Remember:Rules for effective C++ programming vary, depending on the part of C++ you are using. 因为C++有很多的编程范式,在项目开发过程中,明确规范怎么使用C++很重要,这样可以使整

《Effective C++》读书笔记(二)

一.资源管理 资源管理就是我们申请的资源,不管是内存,互斥锁,文件等等,使用过后,都需要归还给系统.C++没有自带的垃圾回收机制,所以自己把握好资源管理是很重要的! 13.以对象管理资源: a)      将一个对象所需要的所有资源放到对象内部,在对象初始化的时候分配资源,并且在对象被销毁的时候将资源释放. b)      我们通常new一个对象,然后通过指针指向对象,在用过后delete掉.但是有时候会忘记delete,或者在delete前函数return了,这时候,这个指针没了,那这个对象的

《Effective java》—–读书笔记

2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己!预计在2016年要看12本书,主要涉及java基础.Spring研究.java并发.JVM.分布式之类的.在今年面试的时候深受打击,到处都是问分布式.集群的?难道现在工作两三年的都这么牛逼了?都在搞分布式.集群之类的? 2016书单如下: 1.深入理解Java虚拟机:JVM高级特性与最佳实践-(已看,预计今年看三遍) 2.Oracle查询优化改写技巧与案例-(已看) 3.Eff

《effective c++》读书笔记1

条款1:视C++为一个语言联邦 C++包括这四个部分: l  C l  Object-Oriented C++ l  Template C++ l  STL n  C++高效编程守则视状况而变化,取决于你使用C++的哪一部分 条款2:尽量以const,enum,inline替换#define 下面这个宏夹带着宏实参,调用函数f: #define CALL_WITH_MAX (a,b)  f((a)>(b)?(a):(b)) 纵使为所有实参加上小括号,看看下面不可思议的事情 int a=5,b=0

[C++11] Effective Modern C++ 读书笔记

本文记录了我读Effective Modern C++时自己的一些理解和心得. item1:模板类型推导 1)reference属性不能通过传值参数传入模板函数.这就意味着如果模板函数需要一个reference类型的参数,必须在模板声明中将其声明为reference,否则,即使使用一个reference类型的变量调用模板函数,类型推导的结果将不带reference属性. 2)constant和volatile属性也不能通过传值参数传入模板函数,但是可以通过reference参数传入这些属性. 3