Swift & Objective-C

Objective-Cの角括弧構文はなぜこんな形?(メッセージ送信の秘密)

iOSの学習を始めて初めてObjective-Cのコードを見ると、戸惑いやすいものです。

読了 6 分
Objective-Cの角括弧構文はなぜこんな形?(メッセージ送信の秘密)のカバー画像

iOSの学習を始めて初めてObjective-Cのコードを見ると、戸惑いやすいものです。

角括弧 [ ] だらけだからです。関数呼び出しのように見えても、ほかの言語とは見た目が大きく異なります。

「なぜこんな形にしたのだろう?」という疑問が残りますよね。

結論から言うと、Objective-Cの角括弧は関数を「呼び出す」のではなく、オブジェクトに「メッセージを送る」ための構文です。この概念さえ押さえれば、見慣れなかった角括弧が突然理解できるようになります。

今日は、この角括弧がなぜこの形なのか、そのルーツから気楽に紐解いていきます。😊


まずは要点をまとめます

まず、この記事で押さえておきたい内容をまとめました。

  1. Objective-Cの角括弧は「オブジェクトにメッセージを送る」という意味です
  2. この構文はSmalltalkという言語から受け継がれました
  3. [객체 메서드] という構造だけわかれば、ほとんど読めます
  4. 内部ではobjc_msgSendという関数に変換されて実行されます

この4点を理解できれば、今日の目標は達成です。


Objective-Cのメッセージ送信構文とは?

通常、ほかの言語でメソッドを呼び出すときは、次のように書きます。

object.method()

一方、Objective-Cでは次のように書きます。

// dog オブジェクトに bark というメッセージを送る
[dog bark];

// count 値を引数として一緒に送る
[dog barkTimes:3];

見た目は慣れませんが、構造は単純です。

[받는객체 보낼메시지]

角括弧を開き、左側にメッセージを受け取るオブジェクト、右側に送るメッセージを書きます。

つまり[dog bark]は、「dog、barkして」と伝える意味になります。

私はこれを「関数呼び出し」ではなく「話しかけること」と捉えると、ずっと理解しやすくなりました。

引数が複数ある場合は、次のように長くなります。

// メッセージ名が setName:age: 2つに分かれる
[person setName:@"チェス" age:20];

コロン(:)ごとに値が1つずつ付くと考えてください。


角括弧はなぜこの形なのか?

Objective-Cの角括弧は、Smalltalkの「メッセージ送信」という思想をC言語に組み込んだ名残です。

話は1980年代初頭までさかのぼります。

Brad CoxとTom Loveという2人がObjective-Cを作りました。

彼らは当時 phổ及していたC言語をそのまま使いながら、そこにオブジェクト指向の概念を加えようとしました。

そのオブジェクト指向の手本がSmalltalkでした。

Smalltalkの中心的な思想は、「すべてはオブジェクトであり、オブジェクト同士はメッセージをやり取りする」というものでした。

課題は、Cの構文を壊さずにこのメッセージの概念を取り入れることでした。

そこでCの構文ではほとんど使われていなかった角括弧を使い、その中をメッセージ送信のための空間にしたのです。

そのおかげで、既存のCコードと混在しても衝突せずに区別できました。

メッセージを「送る」感覚が身につくと、角括弧が使いやすくなります
メッセージを「送る」感覚が身につくと、角括弧が使いやすくなります

この言語は後にNeXTという会社に採用され、Appleが1996年にNeXTを買収したことで、MacとiPhone開発の基盤になりました。

私たちが知るCocoaフレームワークも、ここから生まれました。

見慣れない角括弧1つに、これほど長い歴史が込められているわけです。


ドット(.)構文とは何が違うのか?

最近の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));

1番目にはメッセージを受け取るオブジェクト、2番目には実行するメソッドの名前札(セレクタ)が入ります。

見た目が違っても、最後は1か所に集まります
見た目が違っても、最後は1か所に集まります

この方式は、どのメソッドを実行するかを実行時に決められるため柔軟です。

そのためObjective-Cは、実行中にメソッドを変更したり追加したりする動的な機能に優れていました。

角括弧という見た目の裏に、このような柔軟な構造が隠れていたのです。

数日使えば手になじむ構文です
数日使えば手になじむ構文です

Q&Aでまとめます

Q. 角括弧は必ず覚える必要がありますか?

暗記するというより、[받는객체 보낼메시지]という構造をつかめば自然に読めるようになります。

Q. 今はSwiftを使っていますが、知っておくべきですか?

古いライブラリやサンプルコードは今でもObjective-Cで書かれているため、読めると大いに役立ちます。

Q. 角括弧の中にさらに角括弧がある場合は?

内側の結果を外側が受け取る構造です。内側から外側へ読めば理解できます。


角括弧が単なる奇妙なルールに見えても、「オブジェクトに話しかける構文」だと考え直せば、ずっと親しみやすくなります。

見慣れない構文ほど、そのルーツを知るとむしろ長く記憶に残ります。

この記事が、Objective-Cを少し身近に感じるきっかけになればうれしいです。応援しています!🙌

あわせて読みたい