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)

Q. @ 和前置處理器的 # 一樣嗎?

不是。#include 中的 # 是在編譯前處理的前置處理器指示詞;@ 則是由編譯器直接解析的 Objective-C 編譯器指示詞(directive),兩者的作用不同。

Q. @ 的種類除了這些之外還有很多嗎?

有,而且不少。例如 @protocol、@selector、@try/@catch、@autoreleasepool 等。在較新的語法中,還能用 @[] 陣列、@{} 字典,甚至 @42 這類數值物件,都能透過 @ 簡單建立。

Q. Swift 裡也有 @,對吧?

沒錯。不過意義稍微不同。Swift 的 @ 主要用於標示屬性(attribute),例如 @State 和 @IBOutlet。根源相似,但用途需要分開理解。


程式碼中到處出現的 @ 可能讓人感到陌生,但了解它是「區分 C 與 Objective-C 的界線」後,反而會覺得親切。

只要跟著 @,就能清楚看出物件導向語法從哪裡開始。閱讀 Objective-C 程式碼時記住這個觀點,會輕鬆許多。祝你今天也享受寫程式的樂趣!