类型化常量 (TYPED CONSTANTS)
#define ANIMATION_DURATION 0.3
这是一个预处理器指令,当编译器在代码中发现有 ANIMATION_DURATION 时,就将它替换为 0.3,编译器不知道这个字符串所指代的数值属性。 更好的办法是用常量去替代预处理器定义:
static const NSTimerInterval kAnimationDuration = 0.3
这样清楚地定义了这个常量是什么,类型是 NSTimerInterval。他可以使阅读代码的人容易理解。注意常量的命名,加前缀 k 表示在本地单元(.m)中适用。如果要在外部使用这个常量,应该加上当前class的名字作为前缀:
EOCViewClassAnimationDration
把常量定义在 .h 中是非常不好的实践。
重点是同时声明 static 和 const。const 限定它不能被修改。static 限定定义这个变量所在的转换单元(translation unit)。Objective-C中,每个class(.m文件)有一个转换单元。 如果变量未声明 static,编译器会为它生成一个外部符号。如果其他的转换单元声明了同样名字的变量,程序会报错。
实际上,当用 static 和 const 去定义一个变量时,编译器不只是像 #define 那样去盲找和替换。至少它显现了所属的类型信息。
有时候你想让一个常量暴露在外部,应该这样定义:
//在 .h 中
extern NSString *const EOCStringConstant;
//在 .m 中
NSString *const EOCStringConstant = @"VALUE";
.h 中的关键词 extern 告诉编译器在全局符号表中有一个 EOCStringConstant。意思是编译器可以使用这个常量,只知道它存在于所链接到的二进制文件中,但不必知道它是怎样定义。
这样定义编译器知道这个值不能被更改,并且这个值会被到处使用。
记住
避免预处理器定义。它们不包含类型信息,只是在编译前执行查找替换。它们可以在没有警告下被重新定义,产生不一样的值。
在实现文件中定义转换单元常量如 static const。这些常量不会暴露给全局符号表,因此它们的名字不需要命名空间。
定义全局常量在.h文件中,然后在.m中定义它们的值。这些常量会出现在全局符号表(global symbol table)中,因此它们的名字应该有命名空间,通常以class命为前缀表示。