多用类型常量替代#define预处理指令

340 阅读2分钟

Objective-C或者C语言中在定义常量时,有一个大家都比较习惯的方式,就是用预处理的宏定义常量,比如

#define kAnimationTime  3

这么写有个明显的问题就是缺乏类型信息,在头文件引入时,由于是预编译的指令,常量名称也可能出现冲突。此时可以使用类型常量来解决这个问题。

static const NSTimeInterval kAnimationTime = 3;

在实现文件内部,可以用这种方式代替#define指令。

  • const表示kAnimationTime是一个常量,不可修改。
  • static表示仅在实现文件内部可见,因为oc以一个.m文件为编译单元,static标记的常量仅在当前编译单元生效,如果不加static关键字,编译器会为kAnimationTime建立一个外部符号,此时,如果其他类有常量名重复,编译器将会报错。
  • NSTimeInterval就是当前常量的类型。

所以,外部需要引用常量时,并不需要static关键字,🌰如下:

///头文件中
extern NSString *const KKLLoginNotification;

///实现文件中
NSString *const KKLLoginNotification = @"KKLLoginNotification"
  • 实现文件中声明KKLLoginNotification常量,并且创建了外部符号
  • extern表示将KKLLoginNotification写入全局符号表,这样编译器不需要知道KKLLoginNotification的具体定义,只要知道全局符号表中有KKLLoginNotification,就会允许代码使用KKLLoginNotification。

事实上,这也是UIKit等iOS SDK中定义通知所常用的方式。

最后补充一下常量的命名原则:

  • static标记的常量只在当前编译目标中有效,所以不存在冲突风险,可以添加k为前缀标记,如kAnimationTime
  • 写入外部符号表的常量和其他常量存在名字冲突的风险,全局都要使用的,建议添加全局统一的前缀,个别类使用的,并和当前类相关的常量,建议在统一前缀后在添加对应的类名,比如EOCLoginManagerDidLoginNotification