開始學習 iOS 後,第一次看到 Objective-C 程式碼時,很容易感到困惑。
因為畫面上到處都是中括號 [ ]。看起來像是在呼叫函式,但外觀和其他語言差異太大了。
難免會留下「為什麼要設計成這樣?」的疑問。
先說結論,Objective-C 的中括號不是在「呼叫」函式,而是用來對物件「傳送訊息」的語法。只要掌握這個概念,原本陌生的中括號就會突然變得容易理解。
今天就從這個語法的根源開始,輕鬆拆解中括號為什麼長成這樣。😊
先掌握重點摘要
先整理一下這篇文章可以學到的內容。
- Objective-C 的中括號代表「對物件傳送訊息」
- 這套語法承襲自 Smalltalk 這個語言
- 只要了解
[객체 메서드]這個結構,就能讀懂大部分內容 - 在內部會轉換成
objc_msgSend函式後執行
只要理解這四點,今天的目標就全部達成了。
Objective-C 的訊息傳送語法,到底是什麼?
在其他語言中呼叫方法時,通常會這樣寫。
object.method()
但 Objective-C 會這樣寫。
// dog 對物件傳送 bark 訊息
[dog bark];
// count 將值一併作為引數傳送
[dog barkTimes:3];
外觀看起來陌生,但結構其實很簡單。
[받는객체 보낼메시지]
打開中括號,左邊放接收訊息的物件,右邊寫要傳送的訊息。
因此 [dog bark] 的意思就是「dog,請 bark」。
我把它理解成不是「呼叫函式」,而是「和物件說話」,就覺得容易多了。
有多個引數時,會像這樣延伸。
// 訊息名稱會 setName:age: 分成兩個部分
[person setName:@"哲秀" age:20];
可以把它想成每個冒號(:)後面都會接一個值。
中括號為什麼長這樣?
Objective-C 的中括號,是把 Smalltalk 的「訊息傳送」理念建立在 C 語言之上後留下的痕跡。
故事要回溯到 1980 年代初期。
Brad Cox 和 Tom Love 兩人共同建立了 Objective-C。
他們想在沿用當時流行的 C 語言之餘,再加入物件導向的概念。
那個物件導向的模範正是 Smalltalk。
Smalltalk 的核心理念是「一切都是物件,而物件彼此交換訊息」。
問題在於,必須在不破壞 C 語法的情況下加入訊息這個概念。
因此他們採用了 C 語法中幾乎不會用到的中括號,將其中定義為傳送訊息的空間。
如此一來,即使和既有的 C 程式碼混用,也能避免衝突並加以區分。
這個語言後來被 NeXT 採用,Apple 在 1996 年收購 NeXT 後,它成為 Mac 和 iPhone 開發的基礎。
我們熟悉的 Cocoa framework 也是由此發展而來。
一個陌生的中括號外觀,背後就承載了這麼悠久的歷史。
它和點號(.)語法有什麼不同?
現在看到 Objective-C 程式碼時,也經常會遇到點號(.)語法。
就像 dog.name 一樣。
因此很容易混淆,我把兩者的關係整理成表格。
| 分類 | 中括號語法 | 點號(.)語法 |
|---|---|---|
| 形式 | [dog name] |
dog.name |
| 意義 | 訊息傳送 | 屬性存取 |
| 出現時期 | 早期開始 | Objective-C 2.0(2007 年)之後 |
| 內部運作 | 執行方法 | 實際上轉換成方法 |
有趣的是,點號語法在內部最後也會轉換成中括號訊息。
也就是說,dog.name 執行時會做和 [dog name] 相同的事。
點號語法只是一件讓程式碼看起來更容易閱讀的外衣。
所以我會建議初學者先理解,本質其實是中括號。
中括號裡實際上發生了什麼事?
讓我們再深入一點。
寫成 [dog bark] 時,編譯器會將它轉換成名為 objc_msgSend 的函式呼叫。
// 我們寫的程式碼
[dog bark];
// 在內部大致會轉換成這樣
objc_msgSend(dog, @selector(bark));
第一個位置放接收訊息的物件,第二個位置放要執行的方法名稱標籤(selector)。
這種方式很有彈性,因為可以在執行時決定要執行哪個方法。
因此 Objective-C 很擅長在執行期間變更或新增方法等動態功能。
中括號的外表之下,原來藏著這樣靈活的結構。
用 Q&A 做個總結
Q. 一定要背中括號嗎?
與其死背,只要掌握 [받는객체 보낼메시지] 這個結構,就能自然讀懂。
Q. 我現在使用 Swift,還需要知道嗎?
因為舊版函式庫或範例程式碼至今仍有許多使用 Objective-C 撰寫,能讀懂會很有幫助。
Q. 如果中括號裡又有中括號呢?
這代表外層會再次接收內層的結果。從內往外讀就能理解。
中括號看似只是奇怪的規則,但只要改成「和物件說話的語法」來思考,就會親切許多。
越是陌生的語法,了解它的根源後反而越能長久記住。
希望今天這篇文章能成為你更熟悉 Objective-C 的契機。為你加油!🙌

