第一次打开 Objective-C 代码时,最先引起注意的就是一个明显特征。
那就是到处出现的 @(at 符号)。
@interface、@property,甚至字符串也会写成 @“Hello”。第一次看到时,你可能会想:“这不是拼写错误吧?”
不过,这个 @ 有非常明确的原因。
Objective-C 的 @ 会告诉编译器:“从这里开始不是纯 C,而是 Objective-C 扩展语法。”
今天就来轻松解释一下,为什么这个 @ 会以同样的方式出现在 @interface、@property 和 @“字符串” 前面。
Objective-C 的 @ 到底是什么?
先从核心结论说起。
@ 是一个特殊符号,用来向编译器标记:“这是 Objective-C 特有的语法。”
要理解这一点,需要先了解 Objective-C 的起源。
Objective-C 并不是一种完全全新的语言,而是在 C 语言之上添加面向对象功能的语言。
也就是说,它完整包含 C 语言,同时额外加入了类和消息等功能。
但这会带来一个问题。
从编译器的角度来看,必须区分哪些是原本的 C 语法,哪些是后来添加的 Objective-C 语法。
而用来划出这条边界的标记,就是 @。
为什么偏偏选择 @(at 符号)?
既有星号(*)和井号(#),为什么一定要用 @ 呢?
答案出人意料地实用。
因为在 C 语言的标准语法中,@ 符号完全没有被使用。
我们来回顾一下 C 中使用的字符。
- 变量和函数名:字母、数字、下划线(_)
- 运算符:+、-、*、/、=、& 等
- 预处理器:#(例如:#include)
这份列表中完全没有 @。
所以 Objective-C 的设计者采用了 @。因为它是不会与现有 C 代码冲突的安全符号。
如果不用 @,而是直接把 interface 这个单词作为关键字,那么现有 C 代码中使用 interface 作为变量名的部分就会全部失效。
在前面加上 @,就能从根本上避免这种冲突。
简单来说,@ 就像一个独立抽屉的把手,里面收纳着 Objective-C 专用语法。
@interface、@property、@“字符串” 为什么全都使用 @
现在进入正题。下面说明这三个看起来性质不同的元素为什么都以相同的 @ 开头。
结论是:它们都是“C 中不存在、只有 Objective-C 才有的功能”。
我们逐一来看。
@interface — 用于打开类的骨架(声明)的指令。由于 C 中根本没有类的概念,所以必须用 @ 标记。对应的 @implementation 和 @end 也是同样的原因。
@property — 自动创建对象属性的功能。这同样是纯 C 中不存在的语法,因此会加上 @。
@“字符串” — 这是最有趣的例子。只有引号的“Hello”和 @“Hello” 是完全不同的东西。
我们用表格比较一下。
| 分类 | “Hello” | @“Hello” |
|---|---|---|
| 本质 | C 风格字符数组 | NSString 对象 |
| 所属 | 原有 C 语法 | Objective-C 扩展 |
| 功能 | 简单的字符排列 | 可以使用 length 等方法 |
只需在引号前加一个 @,简单的文字块就会变成“对象”。
这就是需要 @ 的原因。它相当于一条指令:“请把这个字符串创建为 NSString 对象,而不是普通的 C 字符串。”
总结如下。
无论是 @interface、@property,还是 @“字符串”,它们都使用相同的 @ 标记,因为这些都是 C 中不存在、只有 Objective-C 才有的功能。
通过代码一眼看懂
只用语言解释可能有些抽象,所以准备了一个简短的示例。
下面是一个简单的类声明。请观察 @ 是如何包住 Objective-C 语法的。
@interface Person : NSObject // 类声明开始 (CC 中不存在的语法)
@property NSString *name; // 自动生成属性
@end // 声明结束
NSString *greeting = @"你好"; // 引号前 @ → NSString 对象
可以看到,所有以 @ 开头的行都是 Objective-C 新增的功能。
相反,没有 @ 的部分则是从 C 语言直接继承的语法。
这样一来,只要看有没有 @,就能马上分辨:“啊,这是 Objective-C 扩展。”
常见问题(Q&A)
问:@ 和预处理器的 # 是一样的吗?
不是。#include 中的 # 是在编译前处理的预处理器指令;而 @ 是由编译器直接解析的 Objective-C 编译器指令(directive),因此作用不同。
问:除了这些,还有很多种 @ 吗?
有,而且不少。例如 @protocol、@selector、@try/@catch、@autoreleasepool 等。在较新的语法中,还可以使用 @[] 数组、@{} 字典,甚至 @42 这样的数字对象,都能通过 @ 轻松创建。
问:Swift 中也有 @,对吧?
没错。不过含义略有不同。Swift 中的 @ 主要用于标记属性(attribute),例如 @State 和 @IBOutlet。根源相似,但用途需要区分。
代码中到处出现的 @ 可能让人感到陌生,但了解它是“区分 C 与 Objective-C 的边界”后,反而会觉得亲切。
只要跟着 @,就能清楚看出面向对象语法从哪里开始。阅读 Objective-C 代码时记住这个视角,会轻松许多。祝你今天也享受编程的乐趣!

