《iOS 三问》--#define 用法大全

OC 的 #define 命令与在 C 语言中的非常相似,是一个预处理命令,其作用是在编译之前对你的代码进行预处理,使用在 define 中定义的字符串 value 来替换你要替换的字符串 key, 其形式如:

#define 使用格式
1
#define KEY value

这里要注意几点:

  1. #define 预处理命令 顾名思义,是在编译前工作的,所以其优先高于各种编译期间指令,而且享受不到编译器强大的错误提示(所以使用它要格外小心);
  2. 像上面**#define 使用格式**,要注意你的 key 与 value 都不要有空格(除非是字符串用引号括住了);
  3. KEY 一般使用全大写加下划线组合,至少首字母要大写,这样别人在代码人能一眼看出这是个宏。

1 基本使用

我们一般会这样使用,比如在一个头文件中声明

1
#define PI 3.141592654

到后面要使用圆周率时,就不需要每次都使用 3.141592654 这个魔术数字,直接使用 PI 就行,如 perimeter = 2 * PI * raiuds;

1.1 括号问题

使用 define 时,我们建议 value 一般要加上括号,以避免因替换环境引起的错误,如

因替换环境引起的错误
1
2
3
#define padding 20+10

viewWidth = padding * 2;

上面的语句发生错误,本来我们希望的是: viewWidth = (20 + 10) * 2 = 60;
结果被展开成:viewWidth = 20 + 10 * 2 = 40;

所以,使用 define 时,value 处最好都加上括号:

1
#define padding (20 + 10)

2 条件 define

define 还可以用于在编译之前做一个条件判断,在编译前,预处理会进行判断,把不符合条件的代码段屏蔽掉。比如我们常用的

1
2
3
4
5
#ifdef DEBUG
#define MGLog(...) NSLog(__VA_ARGS__)
#else
#define MGLog(...)
#endif

这里就作了一个条件判断,如果在之前使用 #define DEBUG 定义过 DEBUG 这个宏,就保留 if 块中的代码;否则,保留 else 块中的代码。

3 高级使用

3.1 define 函数 - 宏方法

#define 声明中还可以使用参数,并且可使用多个参数;这一特性被称为 “宏方法”:

1
2
3
#define SQUARE(x) ( (x) * (x) )

此时,y = SQUARE (v + 1); 等价于 y = ( (v + 1) * (v + 1) );。

特别注意括号问题,上面的别写成 #define SQUARE (x) ( x * x ),原因自己想。

3.2 多个参数的宏方法

如果参数中有多个参数,可以在 key 中使用 ... 来传入多个参数,在 value 中使用 ##__VA_ARGS__ 来引用传入的参数。如下面的一个便利新建数组的宏方法:

1
2
#define Array(FIRST, ...) [NSArray arrayWithObjects: FIRST, ##__VA_ARGS__, nil]
其中 ##__VA_ARGS__ 用于表示省略号所代表的所有内容。

3.3 #算符以及 ## 算符

# 算符 可产生一个 C - 语言 格式的字符串(这个在 OC 中用得比较少)。如:

1
2
#define string(x) #x
// 则 string (testing) == "testing"

# 算符 用来连接两段字符串。假设你有一组变量,x1 到 x100。如果你想打印其中某一个变量的值。你可以这样定义:

## 算符 可以直接生成复合的变量名!如:

1
2
3
#define printxvar(n) printf("%i\n", x##n)

// 由此,printxvar (20); 在编译时将被识别为 printf (“% i\n”, x20);。这样只需要输入 printxvar (n); 便可以打印出 xn 的值。

其实,## 最常用的用途还是上面介绍的 ##__VA_ARGS__,它可用来抓取省略号所代表的所有内容。

3.4 使用 \ 切分多行宏定义

比如我们常用的 weakify 与 strongify 字义

1
2
3
4
5
6
7
#define weakify(var) __weak typeof(var) AHKWeak_##var = var;

#define strongify(var) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
__strong typeof(var) var = AHKWeak_##var; \
_Pragma("clang diagnostic pop")

4 编程中常用的宏

4.1 表示在模块器中

1
2
#if TARGET_IPHONE_SIMULATOR
#endif

4.2 根据 target 条件编译

可以在项目的 Build Settings 中的 Preprocessor Macros 中设置 target 的预编译宏。然后就可以使用下面的代码来根据不同的 target 跑不同的代码了(一般用于配置)。

1
2
#if defined(BETA)
#endif

5 引用

  1. Kindazrael -《Objective-C #define 用法解析》