Defining object-like macros 定义类对象宏命令

所谓的「宏命令」是一些代码碎片,代码编译完成之后,它就会被预处理器所取代。它有两种形式,其中最基础的是类对象的宏命令(object-like macro)。虽然名字里包含「对象」,但它并不是面向对象编程的那种对象,意思是这些代码会在整体代码编译完成之后,被你所设定的内容代替。

敲黑板嘞,代码编译完成之前,所有的宏命令都被预处理器处理完。所以有时候你会看到 Objective-C 代码好像不太正常,但只要宏命令被正确处理了,仍然会编译成功,而有些代码看起来很好,但是无法编译。

我们用 #define 来新建一个宏命令,在后面跟上宏名称,然后是宏的内容。#define 经常被用来定义常量,比如在 math.h 文件里定义 π 值:

#define M_PI 3.14159265358979323846264338327950288

在这行代码之后,你就可以在代码里面用 M_PI 了,它会自动代替这个 3.14159265358979323846264338327950288 的值。这里并不是函数调用,也不是一个变量,但是当你的 Objective-C 代码中使用了 M_PI 的时候,它就会马上用上这串数字了。这就是宏的便利之处。

你可能奇怪为什么宏命令会用来定义一个常量呢?实话说……真相……其实不是这样……你完全可以这样去定义 π 值:

static const double kPi = 3.14159265358979323846264338327950288;

一般情况下,宏命令都是用大写字母来写的。但这里使用的是「驼峰命名法」,前缀 k 表示的是常量。苹果在它们自己的代码里面,基本上都使用的是驼峰命名法,比如说 kCGBlendModeNormal,但更多地还是用在定义变量里。

在这里,kPi 这个常量会被直接编译,就和用宏命令一样。看起来上面两种写法没有什么区别,但是常量是 Objective-C 语法的一部分,很容易 debug,但是宏命令复杂得多,你无法从字面上轻易地观察到它的值。

除了替换简单值,类对象的宏命令还可以替换具体的代码,这个就没有上面的例子那么好理解了。预处理器不会在意你给宏取个什么名字,以及你想要让它去替换哪个值,所以你可以把整一句代码都用宏命令来代替,比如说你可以这样写:

#define TAYLOR [[Person alloc] initWithName:@"Taylor"];
Person *person1 = TAYLOR
Person *person2 = TAYLOR
Person *person3 = TAYLOR

作为 Objective-C 代码,上面的语法完全是有毒,在语句的后面分号都没有,还创建了三个指向了同一个对象的对象。

但其实预处理器内部是这样处理代码的:

Person *person1 = [[Person alloc] initWithName:@"Taylor"];
Person *person2 = [[Person alloc] initWithName:@"Taylor"];
Person *person3 = [[Person alloc] initWithName:@"Taylor"];

所以到最后这个代码是可以运行的,但是我必须要说这种代码没有什么意义……(捂脸)

如果你最后决定不想用这个宏了,你可以用 #undef 去删掉它。

#undef M_PI

results matching ""

    No results matching ""