Objective-C

Objective-Cとは



Objective-Cは、C言語をベースに、Smalltalk風のオブジェクト指向機能を取り入れたプログラミング言語です。C言語との高い親和性を保ちながら、オブジェクト指向プログラミングの柔軟性と動的な特徴を兼ね備えています。特に、macOSやiOSなどのApple製品向けのアプリケーション開発で広く利用されています。

概要



Objective-Cは、C言語を拡張してオブジェクト指向を実現するというよりは、C言語で記述されたオブジェクト指向システムを使いやすくするために、マクロ的な拡張を施した言語と捉えることができます。そのため、C++のように「より良いC」を目指したのではなく、「Cとオブジェクトシステムの融合」という考え方に基づいています。この結果、Objective-Cは、C言語の基本的な構文に加えて、Smalltalkの概念を基にした動的なオブジェクト指向ランタイムを持ち合わせる独特な言語となりました。

Objective-Cのコードは、関数(メソッド)の定義と呼び出し方が独特であるため、一見するとC言語C++とは大きく異なって見えます。しかし、基本的な文法はC言語と共通であり、if/for/whileなどの制御文、intなどのスカラー型、関数記法などはC言語に準拠しています。一方、オブジェクトシステムはSmalltalkの概念をほぼそのまま借用しており、動的型付けのクラス型オブジェクト指向ランタイムを持ち、メッセージパッシングを通じて動作します。このため、しばしば「インラインでCの書けるSmalltalk」あるいは「インラインでSmalltalkの書けるC」と表現されることがあります。

Objective-Cの特徴的な部分は、`@`で始まるコンパイラディレクティブによって明示され、オブジェクトのメソッド呼び出しは`[]`で囲まれたメッセージ式で行われます。最大の特徴は、オブジェクトシステムが完全に動的である点で、実行時のクラス拡張や、オブジェクト汎用型`id`の導入により、型に依存しない動的な配列や辞書など、インタプリタに近い記述力を持ちます。コード自体はネイティブコンパイルされるものの、動作原理はインタプリタに近く、コンパイラ型言語としては非常に高い柔軟性を発揮します。

C言語の観点から見ると、Objective-Cは一種のスクリプトインタプリタが組み込まれているような状態であり、一方、オブジェクトシステムからは、OSの機能やC言語のリソースを直接利用できるインターフェースが提供されていると解釈できます。仮想マシンを必要としないため、取り回しが良いという利点もあります。パフォーマンスは、Javaのような中間コード型言語よりも優れており、CやC++のようなネイティブコンパイル言語には劣るとされています。Objective-C特有のこの形態は、それぞれの利点と欠点を明確にし、実用性に優れた使い勝手を提供します。

歴史



Objective-Cは、1983年にブラッド・コックスとトム・ラブによって開発され、そのコンパイラやライブラリをサポートするためにStepstone社が設立されました。当初はマイナーな存在でしたが、1985年スティーブ・ジョブズAppleを離れてNeXT Computer社を設立し、NeXTコンピュータとNeXTSTEPオペレーティングシステムの開発に使用されたことで、注目を集めるようになりました。

NeXTのユーザーインターフェースは、Display PostScriptとObjective-Cで記述されたApplication Kitによって提供され、Objective-CはNeXTコンピュータの主力言語となりました。その後、NeXT社はGCCをベースにしたObjective-Cのサポートを行い、プロトコルの導入など文法の拡張を行いました。NeXT社による多くの成果は、GCCにも還元されました。

1995年には、NeXT社がStepstone社からObjective-C言語と商標に関するすべての権利を買い取りました。1997年初頭にはAppleがNeXT社を買収し、2001年に登場したMac OS XのCocoaフレームワークのコア言語として採用されました。Mac OS X v10.5からは、一部の言語仕様が変更され、Objective-C 2.0と呼ばれるようになりました。

コンパイラと言語仕様は完全に公開されていますが、長らくNeXTおよびその後継であるmacOSとiOSの専用言語に近い状態でした。2008年にiPhone OS(現iOS)のAPIが公開されて以降、学習者の数は増加傾向にありますが、Appleの開発環境は、徐々にLLVM/Clangに移行し、GCC版は事実上GNUstep専用となっています。

基本的な構文



Objective-Cの構文は、C言語の構文とオブジェクト指向の概念を組み合わせたものです。以下にその主な特徴を解説します。

メッセージ送信


Objective-Cでは、オブジェクトのメソッド呼び出しは、Smalltalkのメッセージ式を模した独自の構文で行われます。これをメッセージ式と呼び、メソッドの呼び出しをメッセージ送信と表現します。メッセージ送信は実行時のメッセージパッシングであり、その時に渡されるメッセージ値をセレクタと呼びます。特徴的なのは、Smalltalkと同様にキーワード引数形式を取ることで、セレクタ名と引数値が交互に並んだ形式になります。なお、Smalltalkにあるカスケード式(一つのオブジェクトに対して続けてメッセージを送る)は存在しません。

クラス定義


Objective-Cのクラスは、定義部と実装部に分かれており、通常、定義部を`.h`ファイルに、実装部を`.m`ファイルに記述します。また、後述するカテゴリを使用することで、クラス定義を複数のパートに分割できます。

メソッドには、クラスメソッドとインスタンスメソッドがあり、それぞれ接頭辞`+`および`-`で区別されます。クラスメソッドはクラスオブジェクトの操作に使用され、インスタンスメソッドはインスタンスオブジェクトの操作に使用されます。クラスメソッドは、インスタンスオブジェクトの生成にもよく使用されます。

コンストラクタは存在せず、慣習的に新規オブジェクトの生成には`+alloc`を使用し、初期化には`-init`を使用しますが、プログラマは自由に別の特殊化したメソッドを定義できます。デストラクタ(ファイナライザ)に相当するものは`-dealloc`またはガベージコレクション使用時の`-finalize`であり、オブジェクトが破棄される際に必ず呼び出されます。

`self`は特別な変数で、メソッド実行時に自動的にレシーバが代入されます。再代入も可能で、`-init`などでスーパークラスの実装で自分自身を初期化し、正しい値が返された時のみ、初期化を継続する場合などに利用されます。

オブジェクトの型は、オブジェクトを特定のクラスに制限したい場合に使用されます。ただし、これはソースコード上でのみ意味を持ち、実行レベルでは全て`id`として扱われます。また、型付きのオブジェクトはインスタンス変数を構造体互換でアクセスできます。保護レベルは、`public`(フリー)、`protected`(継承クラスのみ)、`private`(同一クラスのみ)があり、デフォルトは`protected`です。ただし、メモリ管理の一貫性などの理由から、ほとんどの場合アクセサを使用します。

互換性



32bit時代のLinux版GCCでは、`NSObject`クラスではなく`Object`クラスが使用されていました。64bit時代になり、`Object`クラスの定義は残っているものの、ほとんどのメソッドが削除され、以前のように`NSObject`クラスの代わりに使用することはできません。ソースコードレベルでの互換性は完全に失われています。代わりにGNUstepを導入し、ヘッダーとして`#import `を記述し、`Object`クラスを`NSObject`クラスに変更する必要があります。また、ライブラリの指定も従来の`-lobjc`だけでは不十分で、`-lgnustep-base`の指定が必要になります。

特徴



Objective-Cには、他の言語には見られない特徴的なメカニズムがいくつか存在します。

リフレクション


Objective-Cのオブジェクトは、自身に関する定義情報を保持しており、実行時に利用できます。これにより、オブジェクトのクラスやメソッドに関する情報を動的に取得し、処理を行うことができます。

転送(Message Forwarding)


実装系に依存しますが、存在しないメソッドを呼び出した際に、例外を発生させる前に、そのメッセージを他のオブジェクトに転送する機会が与えられます。Appleのランタイムでは、セレクタに対応する引数情報と転送処理の二つの過程を経て行われます。

プロトコル


プロトコルは、クラスが実装すべきメソッドのインターフェースを規定する機構です。元々は、分散オブジェクトシステムを構成する際に、リモートオブジェクトの通信効率を向上させるために導入されました。プロトコルに準拠するクラスは、定義されたメソッドを全て実装する必要があります。また、プロトコルは多重継承を許容します。

類似した機構に、実装をオプションにできる`informal`プロトコルがあります。これは、後述するカテゴリのうち、インターフェース定義のみを利用する方法で、利用側は実装状態をリフレクションで調査し、正当な場合のみメソッドを呼び出します。

カテゴリ


カテゴリは、クラス定義をグループに分割したり、既存のクラスにメソッドを追加したりするための言語機能です。Smalltalkが統合開発環境上でクラスとメソッドの表示を整理するために使用しているクラスカテゴリとメソッドカテゴリをそのまま取り入れたものです。カテゴリを使用することで、クラスの実装を関連するメソッド群ごとに分割して記述したり、既存のクラスに対してサブクラスを作成せずにメソッドを追加することができます。また、カテゴリに宣言したメソッドは、カテゴリがロードされたタイミングでクラスに追加されます。

カテゴリで既存のメソッドをオーバーライドすることも可能ですが、推奨されていません。

メモリ管理



Objective-Cのメモリ管理は、初期にはC言語と同様に単純な割当と解放が行われていましたが、現在は標準APIライブラリに実装された参照カウント方式のAutorelease poolを利用するのが一般的です。

手動管理の場合


`NSAutoreleasePool`クラスをインスタンス化し、解放されるべきオブジェクトを、`autorelease`メッセージを使って登録します。登録された全てのオブジェクトが不要になったら、`release`メッセージを使って`NSAutoreleasePool`のインスタンスを解放します。すると、登録されていたオブジェクトも全て一斉に解放されます。

また、オブジェクトのイニシャライザ(初期化メソッド)を呼び出すと、その時点で自分を`autorelease`するオブジェクトを定義できます。このようにしてインスタンス化されたオブジェクトは、`NSAutoreleasePool`のインスタンスを解放するだけで、明示的に`autorelease`しなくても解放できます。例えば、`NSString`クラスの`stringWithCString:`メソッドで初期化すると、`autorelease`された状態になります。

自動参照カウント (ARC)


自動参照カウント(ARC)は、内部的には`retain`/`release`/`autorelease`と同様のメカニズムで動作しますが、コンパイル時にメソッドの命名ルールなどを見て、自動的に`retain`/`release`相当のコードを挿入する方式です。これにより、ARCでは明示的な`retain`/`release`がそもそも不可能になります。管理周りのコードが削減され、`autorelease`管理の実行効率が向上するため、旧方式のプログラムをARCに切り替えるだけでも、パフォーマンスが向上することがあります。

その他



Objective-Cは、動的なディスパッチやオブジェクトシステムがCで記述されているという特徴から、柔軟な超言語的な技法が利用可能です。

メタ言語的メカニズム


  • - posing: クラステーブルを書き換えることで、クラスの実体を置き換える技法です。
  • - method swizzling: クラスのメソッドテーブルを書き換えることで、セレクタ名のリネーミングを行う技法です。
  • - IMP呼び出し: メッセージパッシングの代わりに、一度だけメソッドを解決して関数ポインタを取り出し、メソッド呼び出しを高速化する技法です。

Objective-C++


Objective-CとC++が混在したもので、両言語はCからの拡張部分が干渉しないため、お互いをポインタ値とみなすことで表記が混在できます。拡張子は`.mm`となります。関数やObjective-Cメソッドの内部では、Objective-CとC++の両方の機能を自由に組み合わせて利用できます。例えば、Objective-Cオブジェクトの寿命を管理するスマートポインタを、C++の機能を用いて作成することができます。ただし、クラスの階層はObjective-CとC++で完全に分離されており、一方から他方を継承することはできません。

言語ブリッジ


Objective-CランタイムシステムはC言語関数群で構成されており、リフレクションやメッセージ送信の機構もC言語で記述されています。このため、これらの機構に対するラッパーを用意することで、外部言語からシステムを完全制御することが可能です。現在、言語ブリッジが確立している言語には、Smalltalk、HaskellJavaPerlPython(PyObjC)、RubyRubyCocoa)などがあります。

処理系の特性



Objective-Cの処理系には、Apple/NeXT版、GNU版、Portable Objective-C版などがあります。

Objective-C 2.0



Appleは、Mac OS X v10.5において、Objective-C 2.0として言語仕様の変更を行いました。

ガベージコレクションの導入


世代別の保守的GCを導入し、GC管理下にあるオブジェクトはメモリ管理を自動化できるようになりました。ただし、ガベージコレクションはOS X 10.11を最後に廃止されています。

プロパティの導入


C#などで採用されているプロパティが追加され、setter/getterの記述が大幅に簡略化されました。また、Key-Value-Codingに関してドット記法が導入され、`obj.propName`のようなアクセスが可能になりました。

Fast Enumeration


いわゆる`foreach`文が導入されました。

プロトコルの強化


実装オプションのプロトコル定義が増えました。

Class Extensions


実装をオプションにできない無名カテゴリです。実装必須のプライベートメソッドを、インターフェース的に公開したくない場合に使用されます。Objective-Cでは動的ディスパッチを行うため、非公開メソッドでも呼び出しに制限がない点に注意が必要です。

ランタイム構造の変更


クラスのposingは廃止されました。代わりにメソッドの交換(セレクタのマッピングを入れ替える)が公式に用意され、カテゴリと組み合わせることでほぼ同じ機能を実現できます。その他にも、ランタイム周りは大幅に変更されています。


Objective-Cは、柔軟性と動的な特徴を持つ強力な言語であり、特にApple製品のアプリケーション開発において重要な役割を果たしています。その歴史と特徴を理解することで、より深くObjective-Cを活用することができるでしょう。

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。