《Effective Objective-C 2.0 》 阅读笔记 item4

第4条:多用类型常量,少用#define预处理指令

1. 用#define预处理指令定义常量

#define ANIMATION_DURATION 0.3;

解释:常量没有类型信息,并且其含义不明确。此外,在预处理过程中会把碰到的所有ANIMATION_DURATION一律替换成0.3。

2. 类型常量

static const NSTimeInterval kAnimationDuration = 0.3;

 

解释:这种方式定义的常量包含类型信息,且清楚地描述了常量的含义。

3.类型常量的命名

3.1 常量局限于某“编译单元”(即实现文件)

若不打算公开某个常量,则应将其定义在使用该常量的实现文件里。

如:

static const NSTimeInterval kAnimationDuration = 0.3;

变量一定要同时用static与const来声明。

  • 如果试图修改由const修饰符所声明的变量,那么编译器就会报错。
  • 而static修饰符则意味着该变量仅在此变量的编译单元中可见。如果声明此变量时不加static,则编译器会为它创建一个“外部符号”(external symbol)。此时若是在另外一个编译单元中也声明了同名变量,那么编译器就抛出错误信息。

实际上,如果一个变量既声明为static,又声明为const,那么编译器根本不会创建符号,而是会像#define预处理指令一样,把所有遇到的变量都替换为常值。

3.2 常量在类之外可见

有时候需要对外公开某个常量。最常见的例子是:用字符串来表示通知的名称,并将其声明为一个外界可见的常值变量。这样,只需以常量变量来注册自己想要接收的通知即可。
此类常量需放在“全局符号表”(global symbol table)中,以便可以在定义该常量的编译单元之外使用。

如:

/* 头文件 “声明”  */
extern NSString *const EOCLoginManagerDidLoginNotification;

/* 实现文件 “定义”  */
NSString *const EOCLoginManagerDidLoginNotification = @"EOCLoginManagerDidLoginNotification";

 

  • 注意const修饰符在常量类型中的位置。对此的解读是“一个常量,而这个常量是指针,指向NSString对象”。
  • extern关键字会告诉编译器:在全局符号表中将有一个名叫EOCLoginManagerDidLoginNotification的符号。换言之,编译器无须查看其定义,即允许代码直接使用此常量
  • 此类常量必须要定义,而且只定义一次。通常,将其定义在与声明该常量的头文件相关的实现文件里。注意,该常量所指向的字符串的存储空间被分配在“数据段”(data section)中。
  • 此类常量的命名最好是用与之相关的类名做前缀。

这样,所定义的常量要优于使用#define预处理指令。因为编译器会确保常量值不变。

要点

  • 不要用预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作。即时有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
  • 实现文件中使用static const来定义“只在编译单元内可见的常量”(translation-unit-specific constant)。由于此类常量不在全局符号表中,所以无须为其名称加前缀。
  • 头文件中使用extern来声明全局常量,并在相关实现文件中定义其值。这种常量要出现全局符号表中,所以其名称应加以区隔,通常用与之相关的类名做前缀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉亭下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值