预处理指令是以 #
号开头的代码行。#
号必须是该行除了任何空白字符外的第一个字符。#
后是指令关键字,在关键字和#
号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。
# // 空指令,无任何效果
#import “" // 导入一个源代码文件
#include “” // 包含一个源代码文件
#define macro // 定义宏
#undef macro // 取消定义宏
#if condition // 条件编译指令,如果满足condition,则编译以下内容
#ifdef // 条件编译指令,如果定义了,则往下编译
#ifndef // 条件编译指令,如果没有定义,则往下编译
#elif // 如果前面的 #if 不为真,当前条件为真,则往下编译
#endif // 结束条件编译块
#error // 停止编译,并显示错误信息,一般用于条件编译
-
导入/包含文件
#import
跟#include
大部分功能是一样的,但是他处理了重复引用的问题,我们在引用文件的时候不用再去自己进行重复引用处理。例如:有 A.h B.h C.h三个头文件
A.h需要引入B.h 和 C.h, 而B.h也引入C.h 这样就构成了重复引用,使用#import
就可以避免这种情况。有两种引入方式,一种使用尖括号
< >
,告诉编译器在编译器自带的或外部库的头文件中搜索被包含的头文件,另一种使用双引号""
,表示在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不 到,再搜索编译器自带的头文件。在OC中应尽量少在类的头文件中引入其他头文件,如果需要在头文件中用到引入的头文件,首先考虑向前声明(forward declaring),将引入头文件的时机尽量延后,只有在有需要时才引入。
@class YourClass
在这种不需要知道
YourClass
类的全部细节,只需要知道有一个类名叫YourClass
就好的情况下,使用向前声明可以减少编译时间,提高效率。然而有些协议,比如“委托协议”就需要知道协议内容,这时候不能使用向前声明,应该考虑在类的扩展 class-continuation category 中实现,这样的话需要在实现文件中引入包含的委托协议头文件即可,而不需要将其放在公共头文件中。
要点:
- 除非有必要,否则不要引入头文件,一般来说,应在某个类的头文件中使用向前声明来提及别的类,并在实现文件中引入那些类的头文件。这样做可以尽量降低类之间的耦合。
- 有时无法使用向前声明,比如要声明某个类遵循意一项协议,这种情况下,尽量把该类遵循的某协议的这条声明移至 class-continuation category中。如果不行的话,就把协议单独放在一个头文件中,然后将其引入。
-
宏定义
用
#define
定义一个宏,用#undef
取消定义一个宏,宏的定义在编译时只是简单的替换#define TEST_MACRO 100 // 定义宏 int array[TEST_MACRO]; // 使用定义的宏 #undef TRST_MACRO // 取消定义宏 #define VALUE1 10 #define VALUE2 20 #define VALUE (VALUE1 + VALUE2)
注意:
定义宏常用大写字母作为宏名
在定义宏的时候,后面如果有计算,习惯于使用括号
宏定义可以定义一个函数 例如:#define SQUARE(x) (x * x) int square = SQUARE(5);
-
# 运算符
#
运算符将参数转换为一个字符串 例如:#define TEST(n) @"SHIT"#n NSLog(@"%@",TEST(ON)); // 此时将ON作为字符串拼接到“SHIT”后面
控制台输出为
2017-08-19 15:02:30.165640+0800 VowelMovement[7289:370495] SHITON Program ended with exit code: 0
-
## 运算符
##
运算符的作用是将出现在其两侧的参数合并 例如:#define TEST(x, y, z) x##y##z NSLog(@"%d", TEST(1, 2, 3));
控制台输出结果
2017-08-19 15:08:32.405656+0800 VowelMovement[7336:375139] 123 Program ended with exit code: 0
-
条件编译指令
#if
指令:检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else
、#elif
或#endif
为止;否则就不编译。#endif
用于终止#if
预处理指令#ifdef
和#ifndef
:#ifdefined
等价于#ifdef
;#ifdefined
等价于#ifndef#else
指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。#endif
指令将中指上面的条件块。-
#elif
预处理指令综合了#else
和#if
指令的作用。#ifdef TEST printf("defined TEST"); #else printf("no define"); #endif
Reference:
《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》