-
少用#define预处理指令,多用类型常量
在写代码时尽量不要用预处理指令(#define)来定义常量,因为这样定义出来的常量不包含类型信息。
如:
#define ANIMATION_DURATION 0.3 // 定义一个动画播放时间
编译器在编译前根据此执行查找与替换操作。即使在后面重新定义了常量值,编译器也不会产生警告,这可能会导致在应用程序中运行时获取的常量值不一致。
因为Objective-C没有“命名空间”这一概念,这样就有互相冲突的可能了,如果在头文件声明了预处理指令,那么所有引入了所有这份头文件的其他文件里都会出现这个名字。
为了解决这个问题,如果不打算公开某个预处理指令常量,将其常量定义在实现文件( .m)里,利用编译器的特性:
// 如果视图修改const修饰的变量,编译器就会报错。
// static意味着该变量尽在定义此变量的编译单元(通常指每个类的实现文件)中可见。
static const NSTimeInterval kAnimationDuration = 0.3;
如果不加static,另一个编译单元也声明了同名变量的话,编译器会抛出一条错误信息。
duplicate symbol _kAnimationDuration in:
EOCAnimatedView.o
EOCOtherView.o
这样更清晰地描述了常量的含义和类型,有利于编写开发文档,在定义了大量常量后,这种方式能令稍后阅读代码的人更容易理解其意图。
有时候如果需要对外公开某个常量,比如在使用调用NSNotificationCenter来通知他人的时候。派发通知时,需要使用字符串来表示通知名称,这个名字可以声明一个为外界可见的常值变量,此类变量需放在“全局符号表”中,以便定义该变量的编译单元之外使用。
// .h
// 编译器看到extern关键字,默认全局符号表中将有一个EOCStringConstant的符号
// 编译器知道,当链接成二进制文件后,就能找到这个常量
extern NSString *const EOCStringConstant;
// .m
// 一个指针常量,指向NSString对象
NSString *const EOCStringConstant = @"VALUE";
此类常量必须定义且只能定义一次。实现文件生成目标文件时,编译器会在“数据段”(data section)为字符串分配存储空间。凡使用到 EOCStringConstant 这个全局符号的地方,里,链接器就能将其解析。
因此,命名常量时需谨慎,最好用与之相关的类名做前缀,系统框架一般都会这样做。
例如UIKit中,有UIApplicationDidEnterBackgroundNotification这样的常量名。
假如要将EOCAnimatedView类的动画播放时长对外公布,可以这样声明:
// EOCAnimatedView.h
extern const EOCAnimatedViewAnimationDuration;
// EOCAnimatedView.m
const NSTimeInterval EOCAnimatedViewAnimationDuration = 0.3;
这样定义,编译器能保证常量值不变,亦可随处使用。
-2021.02.25
网友评论