define定义了一个宏,在编译开始之前就会被替换。
const只是对变量进行修饰,当试图去修改该变量的时候,编译器会报错。在一些场合里只能用#define,而不能用const。理论上,const不仅在运行时需要占用空间,而且还需要一个内存的引用。但是从时间上来说,这是无关紧要的,编译器可能会对其进行优化。
const在调试和编译的时候,比#define更友好。在大多数情况下,当你决定用哪一个时,这是你应该考虑的一个非常重要的点。
想象一下下面的应用使用#define而不是const的场景:如果想在大量的.c文件中使用一个场景,只需要使用#define放在头文件中;而是用const,则需要在.c文件和头文件中都进行定义。如下所示:
//in a c file
const int MY_INT_CONST = 12345;
//in a header
extern const int MY_INT_CONST;
MT_INT_CONST,在任何C文件中都不能当作一个全局变量或者一个全局作用域来使用,除非它已经被定义。然而,对于一个整型常量,你可以使用枚举(enum)。事实上,这就是Apple一直在做的事情。它(enum)兼有#define和const的所有优点,但是只能用在整型常量上。
//in a c file
enum{
MY_INT_CONST = 12345,
};
哪一个更高效或者更安全呢?#define在理论上说更高效,但就像之前说的那样,在现代的编译器上,他们可能没有什么不同。#define会更安全,因为当试图赋值给它时,总会出现一个编译器错误。
因此,相对于字符串字面量或数字,更推荐适用常量。应使用static方式声明常量,而非使用#define的方式来定义宏。
恰当用法如下:
static NSString * const LDCAboutViewControllerCompanyName = @"The New York Times Company";
stattic const CGFloat LDCImageThumbnailHeight = 50.0;
不恰当用法如下:
#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
对于整型类型,代替#define比较好的方法是使用enum,在使用enum时,推荐使用罪行的fixed underlying type规范的NS_ENUM和NS_OPTIONS宏,因为他们属于C语言的枚举,保留了C语言的简洁和简单的特色。这些宏能明确指定枚举类型,大小和选项,改善在Xcode中的代码质量。此外,在旧的编译器中,这种语法声明能够正确编译通过,在新的编译器中,也可明解基础类型的类型信息。
下面,使用NS_ENUM来定义枚举。该组值是互斥的,代码如下:
typedef NS_ENUM(NSInterger,UITableViewCellStyle){
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
在本例中,在命名UITableViewCellStyle的NSInteger类型时,通过使用NS_ENUM宏使界定双方和枚举类型更容易了。
在下面的代码中,通过使用NS_OPTIONS宏定义了一组可以组合在一起的位掩码值,实现方式如下:
typedef NS_OPTIONS(NSUnterger,UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexbleLeftMargin = 1 <<0,
UIViewAutoresizingFlexbleWidth = 1 <<1,
UIViewAutoresizingFlexbleRightMargin = 1<<2,
UIViewAutoresizingFlexbleTopMargin = 1 <<3,
UIViewAutoresizingFlexbleHeight = 1 << 4,
UIViewAutoresizingFlexbleBottomMargin = 1 << 5
};
像枚举一样,NS_OPTIONS宏定义了一个名称和一个类型。然而,对于选型的类型通常应该是NSUInteger。
要点######
(1)尽量避免使用#define预处理命令。#define预处理命令不包含任何的类型信息。仅仅是在编译前做替换工作。他们在重复定义时不会发出警告,容易在整个程序中产生不一致的值。
(2)在源文件(.m)中定义的static const类型常量因为无须全局引用,所以他们的名字不需要包含命名空间。
(3)在头文件(.h)中定义的全局引用的常量,需要关联定义在源文件(.m)中的部分。因为需要被全局引用,所以他们的名字需要包含命名空间,通常是用他们的类名作为命名前缀。
(4)尽量用NS_ENUM和NS_OPTIONS宏来实现枚举。
网友评论