52个有效方法(4) - 多用类型常量,少用#define预处理指令
局部常量
在实现文件中使用 static const 来定义“只在编译单元内可见的常量”(translation-unit-specific constant)。其命名规则为在前面加字母k
//
// EOCAnimatedView.h
//
#import <UIKit/UIKit.h>
@interface EOCAnimatedView : UIView
@end
//
// EOCAnimatedView.m
//
#import "EOCAnimatedView.h"
static const NSTimeInterval kAnimataionDuataion = 0.5;
@implementation EOCAnimatedView
@end
-
static const 与
#define
-
编译时刻:
#define
是预编译(编译之前处理),const是编译阶段。 -
编译检查:
#define
不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。 -
#define
的好处:#define
能定义一些函数,方法。 const不能。 -
#define
的坏处:使用大量#define
,容易造成编译时间久,每次都需要重新替换。 -
在确定了使用的常量类型,及常量值时使用 const 进行定义;而简单的函数,或传参字符串等高级定义时,则使用
#define
进行宏定义。
-
全局常量
在头文件中使用extern const 来声明全局常量,并在相关实现文件中定义其值。其命名规则为以类名为前缀。
//
// EOCAnimatedView.h
//
#import <UIKit/UIKit.h>
extern NSString *const EOCAnimatedViewStringConstant;
extern const NSTimeInterval EOCAnimatedViewDuration;
@interface EOCAnimatedView : UIView
@end
//
// EOCAnimatedView.m
//
#import "EOCAnimatedView.h"
NSString *const EOCAnimatedViewStringConstant = @"VALUE";
const NSTimeInterval EOCAnimatedViewDuration = 3.3;
@implementation EOCAnimatedView
@end
这个常量在头文件中"声明",且在实现文件中"定义".
注意const
修饰符的位置,常量定义应该从右至左解读,所以在示例中, EOCAnimatedViewStringConstant
就是"一个常量, 而这个常量是指针, 指向NSString对象".这与需求是相符的,因为我们不希望有人改变此指针常量.使其指向另外一个NSString对象.
还要说一点就是因为符号要放在全局符号表中,所以一定要注意常量的命名规范.避免名称冲突,最好使用与之相关的类名做前缀.系统框架中一般都是这么做的.
-
extern const 与
#define
-
#define
只是简单的替换,又称作宏定义、预处理命令。 -
extern
与const
联合使用时,const
是要分配内存空间的,提示编译器遇到此变量和函数时在其他模块中寻找其定义 -
#define
是不会对数据类型进行检查 -
extern
与const
联合使用时,是会对数据类型进行安全检查 -
在shared libraries的情况下,
#define
(相当于使用@""
写法的“字面量”
)不能保证得到的字符串地址是一样的。如果用@""
的字符串作为dictionary
的key
的话,会导致它需要做isEqualToString的比较 -
在
shared libraries
的情况下,用extern NSString * const
,只要做指针的比较。显然指针比较比逐个字符比较快多了。
@""
写法的字符串会在编译期被替换成NSConstantString的实例,NSString也是唯一一种可以在编译期被实例化的类
要点
-
不要用预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只会在编译前据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
-
在实现文件中使用static const 来定义“只在编译单元内可见的常量”(translation-unit-specific constant)。一个编译单元就是一个.m文件。由于此常量不在全局符号表中,所以无需为其名称加前缀(在其前面加字母k)
-
在头文件中使用extern const来声明全局常量,并在相关实现文件中定义其值。这种常量要出现在全局符号表中,所以其名称应加以区分,通常用与之相关的类名做前缀。