Swift 与 Objective-C

Objective-C 的 @(at 符号)语法:为什么所有内容都以 @ 开头?(完整总结)

第一次打开 Objective-C 代码时,最先引起注意的就是一个明显特征。

4 分钟阅读
Objective-C 的 @(at 符号)语法:为什么所有内容都以 @ 开头?(完整总结) 封面图

第一次打开 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 专用语法。

@ 划分了 C 原有内容与 Objective-C 添加内容之间的边界
@ 划分了 C 原有内容与 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 代码时记住这个视角,会轻松许多。祝你今天也享受编程的乐趣!