编写代码时经常定义常量,例如: #define ANIMATION_DURATION 0.3,上述预处理指令会把源代码中的ANIMATION_DURATION字符串替换为0.3。这可能就是你想要的效果,不过这样定义出来的常量没有类型信息;此外预处理指令会把碰到的所有ANIMATION_DURATION一律替换成0.3,这样的话,假设此指令声明在某个头文件中,那么所有引入了这个头文件的代码,其ANIMATION_DURATION都会被替换。
要想解决此问题,应该设法利用编译器的某些特性才对。有个办法比预处理指令来定义常量更好,比方说,下面这行代码就定义了一个类型为NSTimeInterval的常量:
static const NSTimeInterval kAnimationDuration = 0.3;
请注意,用此方法定义的常量包含类型信息,其好处是清楚地描述了常量的含义。由此可知该常量类型为NSTimeInterval,这有助于为其编写开发文档。如果要定义许多常量,那么这种方式能令后面阅读代码的人易懂,命名规则是在前面加字母k;若常量在类之外可见,则通常以类名为前缀。
定义常量的位置很重要,我们总喜欢在头文件里声明预处理指令,这样做真的很糟糕,当常量名称有可能互相冲突时更是如此,例如ANIMATION_DURATION这个常量名就不该用在头文件中,因为所有引入了这份头文件的其他文件中都会出现这个名字,其实就连用static const定义的那个常量也不应该出现在头文件里。因为Objective-C没有“名称空间”这一概念,所以那样做等于声明了一个名叫kANIMATION_DURATION的全局变量。此名称应该加上前缀,以表明其所属的类,例如可改为AVViewClassAnimationDuration,若不打算公开某个常量,则应将其定义在使用该常量的实现文件里。
变量一定要同时用static与const来声明,如果视图修改由const修饰符所声明的变量,那么编译器就会报错。而static修饰符则意味着该变量仅在定义此变量的编译单元中可见。加入声明此变量时不加static,则编译器会为它创建一个“外部符号”(external symbol)。此时若是另一个编译文件中也声明了同名变量,那么编译器就抛出一条错误信息:
duplicate symbol _kANIMATION_DURATION in:
第一个文件中...
第二个文件中...
实际上,如果一个变量既声明为static,又声明为const,那么编译器根本不会创建符号,而是会像#define预处理指令一样,把所有遇到的变量都替换为常值。不过还是要记住:用这中方式定义的常量带有类型信息。
有时候需要对外公开某个信息。比方说,你可能要在类代码中调用NSNotificationCenter以通知他人。用一个对象来派发通知,令其他预接收通知的对象向该对象注册,这样·就能实现此功能了,派发通知时,需要使用字符串来表示此项通知的名称,而这个名字就可以声明为一个外界可见的常值变量(constant variabel)。这样的话,注册者无需知道实际字符串值,只需以常值量来注册自己想要接收的通知即可。
此常量需放在“全局符号表(global symbol table)”中,以便可以在定义该常量的编译单元之外使用。因此,其定义方式与上面的static const有所不同。应该这样定义:
// In the header file
extern NSString *const AVStringConstant;
// In the implementation file
NSString *const AVStringConstant = @"VALUE";
这个常量值在头文件中“声明”,且在实现文件中“定义”。注意const修饰符在常量类型中的位置,常量定义应从右至左解读,所以AVStringConstant就是“一个常量,而这个常量是指针,指向NSString对象”。这与需求相符:我们不希望有人改变此指针常量,使其指向另一个NSString对象。