Objective-C

Objective-C（オブジェクティブ シー）は、プログラミング言語の一種。CをベースにSmalltalk型のオブジェクト指向機能を持たせた上位互換言語である。
Objective-CはNeXT、macOSのオペレーティングシステム (OS) に標準付属する公式開発言語である。macOSのパッケージ版に開発環境がDVDで付属するほか、ユーザ登録をすれば無償でダウンロードできる（Xcodeの項目参照）。現在では主にAppleのmacOSやiOS上で動作するアプリケーションの開発で利用される。
概要.
Objective-CはCを拡張してオブジェクト指向を可能にしたというよりは、Cで書かれたオブジェクト指向システムを制御しやすいようにマクロ的な拡張を施した言語である。したがって、「better C」に進んだC++とは異なり、「C & Object System」という考え方であり、ある意味2つの言語が混在した状態にある。
関数（メソッド）の定義と呼び出し方が独特であるため、Objective-Cのコードは一見C++以上にCとはかけ離れた独特の記述となる。しかし、言語仕様はCの完全上位互換であり、if/for/whileなどの制御文や、intなどのスカラー型、関数記法、宣言・代入といった基本的な文法はCに準拠する。一方オブジェクトシステムはSmalltalkの概念をほぼそのまま借用したもので、動的型のクラス型オブジェクト指向ランタイムを持ち、メッセージパッシングにより動作する。このことからしばしば「インラインでCの書けるSmalltalk」または「インラインでSmalltalkの書けるC」などと呼ばれる。Cとは異なるObjective-Cに特有の部分は、codice_1で始まるコンパイラディレクティブで明示され、オブジェクトのメソッド呼び出しはcodice_2codice_3で囲まれたメッセージ式で行われる。
最大の特徴はオブジェクトシステムが完全に動的という点で、実行時のクラス拡張、オブジェクト汎用型idの導入により型によらない動的配列・辞書など、インタプリタに近い記述力をもつことである。実際にコードそのものはネイティブコンパイルされるものの、動作原理はほぼインタプリタに近く、コンパイラ型言語としてはまれな柔軟性を発揮する。
したがって、C側から見れば一種のスクリプトインタプリタが乗っているような状態であり、逆にオブジェクトシステムからはOS機能や膨大なC言語資源を直接利用可能なインターフェースが備わっているといえる。また仮想マシンを持たずに済むため、取り回しも良い。パフォーマンスはJavaのような中間コード型言語よりも良好で、CやC++のようなネイティブコンパイル言語には劣るとされる。Objective-C特有のこの形態は双方のメリット・デメリットが明確で、実際的な使い勝手が非常に優れている。この特性に着目したのがNEXTSTEPで、UNIXとの互換性と先進的なオブジェクト指向環境の両立に成功し、その後のOS設計に大きな影響を与えることとなった。
後続言語への影響としては、特にJavaの基礎設計にその姿を見ることができる（サン・マイクロシステムズがOPENSTEPに関わっていたことと関係がある）。
歴史.
Objective-Cは、1983年にとTom Loveによって開発され、そのコンパイラやライブラリを支援するためにStepstone社を創立した。Stepstone社は、Objective-Cに力を注いだが、それはマイナーな存在であった。Objective-Cが認知され始めるきっかけは、1985年、Apple Computerを去ったスティーブ・ジョブズが、m68k機であるNeXTコンピュータとNeXTSTEPオペレーティングシステムの開発を行うNeXT Computer社を創立したことに始まる。
そのマシンのユーザインタフェースは、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と呼ばれる（詳細は#Objective-C 2.0を参照）。
コンパイラおよび言語仕様は完全に公開されているものの、長らくNeXTおよびその後継であるmacOSとiOSの専用言語に近い状態にある。2008年にiPhone OS（現iOS）のAPIが公開されて以降、習得者の人口が増える傾向にあるが、Appleの開発環境は、徐々にLLVMベースにシフトし、GCC版は事実上のGNUstep専用と化している。
基本的な構文.
メッセージ送信.
C++とは異なり、オブジェクトのメソッド呼びだしにはSmalltalkのメッセージ式を模した新たな構文が導入されている。Objecitve-Cではこれをメッセージ式と呼び、メソッド呼びだしはメッセージ送信と呼ぶ。メッセージ送信は実行時のメッセージパッシングであり、その時渡されるメッセージ値をセレクタという。特徴的なのはSmalltalk同様キーワード引数形式をとることで、セレクタ名と引数値が交互に並んだ形態になる。なおSmalltalkにはあるカスケード式（一つのオブジェクトに続けてメッセージを送る）はない。
// メッセージの送信
// 単項メッセージ
[receiver msg];
// 引数付きメッセージ。この場合「msg:with:」でセレクタ一つ
val = [receiver msg: arg1 with: arg2];
// メッセージの入れ子
val = [obj1 msg: [obj2 msg]];
クラス定義.
Objective-Cのクラスは定義部と実装部に分かれており、通常定義部を.hファイル、実装部を.mファイルに記述する。後述のカテゴリによりクラス定義を複数のパートに分割できる。
// クラスの定義 (MyObject.h)
@interface MyObject : NSObject
 int val;
 id obj;
+ (void)classMethod:(id)arg; // クラスメソッド
- (id)method:(NSObject*)arg1 with:(int)arg2; // インスタンスメソッド。arg1は型付き
@end
// 実装 (MyObject.m)
@implementation MyObject
+ (void)classMethod:(id)arg
 // some operation
- (id)method:(NSObject*)arg1 with:(int)args2
 return obj;
// 典型的なinit
- (id)init
 self = [super init]; // スーパークラスの呼びだし
 if(self != nil)
 val = 1;
 obj = [[SomeClass alloc] init];
 return self;
// deallocは自身のリソースを解放してからスーパークラスに回す
- (void)dealloc
 [obj release];
 [super dealloc];
@end
メソッドにはクラスメソッドとインスタンスメソッドがあり、それぞれ接頭辞codice_4及びcodice_5により区別される。クラスメソッドはクラスオブジェクトの操作に、インスタンスメソッドはインスタンスオブジェクトの操作に使用される。クラスメソッドは特にインスタンスオブジェクトの生成にも使用される事が多い。インスタンスメソッドは、インスタンスオブジェクトにメッセージを送信した際に起動され、クラスメソッドはクラスオブジェクトにメッセージを送信した際に起動する。なお、インスタンスメソッドとクラスメソッドは全く同じ名前のセレクタを指定して定義できる。
いわゆるコンストラクタは存在しない。慣習として新規オブジェクトの生成はcodice_6で、初期化はcodice_7で行われるが、プログラマが自由に別の特殊化したメソッドを定義することが可能であり、初期化中に別の初期化メソッドを呼びだす場合もある。一方デストラクタ（ファイナライザ）に相当するものはcodice_8、またはガベージコレクション使用時のcodice_9で、これらのメソッドはオブジェクトの破壊時に必ず呼び出される。
[[this (プログラミング)|self]]は特殊な変数で、メソッドの実行時に自動的にレシーバが代入される。再代入も可能であり、codice_7等でスーパークラスの実装で自分自身を初期化し、正しい値が返った時のみ継続して初期化を行なうなどに利用される。
オブジェクトの型はオブジェクトを特定のクラスに制限したい時に用いられる。ただしこれはソースコードでのみ意味を持ち、実行レベルでは全てcodice_11として扱われる。また型付きのオブジェクトはインスタンス変数を構造体互換でアクセスできる。保護レベルはcodice_12（フリー）、codice_13（継承クラスのみ）、codice_14（同一クラスのみ）があり、デフォルトはcodice_13である。ただメモリ管理の一貫性などの理由から、ほとんどの場合[[アクセサ]]を用いる。
互換性.
32bit時代のLinux版GCCではNSObjectクラスではなく、Objectクラスが使用されていた。64bit時代になってからは、かろうじてObjectクラスの定義が残っているものの殆どのメソッドは削除され、かつてのようにNSObjectクラスの代わりに使用することは出来ない。ソースコードレベルでは完全に互換性が失われている。代わりにGNUStepを導入し、ヘッダーとしてcodice_16を記述し、ObjectクラスをNSObjectクラスに変更する必要がある。また、ライブラリの指定も従来のcodice_17だけでは足りず、codice_18の指定が必要となる。
特徴.
リフレクション.
Objective-Cのオブジェクトは全て自分自身に関する定義情報を保持しており、実行時に利用することができる。
リフレクションの一部.
- (BOOL)respondsToSelector:(SEL)aSel;
- (BOOL)isKindOfClass:(Class)cls;
転送.
実装系によるが、存在しないメソッドを呼びだした際、例外を発生する前にそれを他のオブジェクトに転送するチャンスが与えられる。[[メッセージ転送|Message Forwarding]]と呼ばれる。
転送の例.
Appleの[[ランタイムライブラリ|ランタイム]]では、セレクタに対応する引数情報と転送処理の二つの過程を経て行われる。
// NSMethodSignatureはメソッドの引数の数や型情報を表すオブジェクト
// Objective-Cのメソッドはスカラー型をとるC関数互換なので正確なスタック情報が必要となる
- (NSMethodSignature*)methodSignatureForSelector:(SEL)sel
 id signature = [otherObj methodSignatureForSelector: sel];
 return signature;
// NSInvocationはターゲットと引数を持ち、返値を受け取るオブジェクト
// 元のターゲットの代わりに別のターゲットで実行を行なうとあたかもそのオブジェクトにメッセージが送られたかのように動作する
- (void)forwardInvocation:(NSInvocation*)invocation
 SEL aSel = [invocation selector];
 if([otherObj respondsToSelector: aSel])
 [invocation invokeWithTarget: otherObj];
 else
 [self doesNotRecognizeSelector: aSel];
プロトコル.
プロトコルはクラスのメソッドインターフェースを規定する機構である。元々はNeXTワークステーション上で分散オブジェクトシステムを構成する際、リモートオブジェクトの通信効率を上げるために導入された。
プロトコルに準拠するクラスは定義されたメソッドを全て実装しなければならない。また、プロトコルは多重継承を許す。
プロトコルの例.
// プロトコルを定義する
@protocol MyProtocol <NSObject, NSCopying>
- (void)methodForRespond;
@end
// プロトコルを導入する
@interface MyObject <MyProtocol>
@end
類似した機構に実装をオプションにできるinformalプロトコルがある。これは後述のカテゴリのうち、インターフェース定義のみを利用する方法で、利用側は実装状態をリフレクションで調査して正当な場合のみ呼びだす。
// ここでは「NSObjectにはtransferAcceptable:が定義されている」と宣言している
// 実際には対応する実装を用意する義務がないため、NSObjectを継承したオブジェクトがそれを行なった場合のみ利用できる
@interface NSObject (OptionalMethods)
- (BOOL)transferAcceptable:(id)obj;
@end
- (void)method
 id val,obj;
 if([obj respondsToSelector: @selector(transferAcceptable:)])
 [obj transferAcceptable: val];
カテゴリ.
カテゴリは、クラス定義をグループに分割したり、既存のクラスにメソッドを追加したりするための言語機能。Smalltalkが統合開発環境上でクラスとメソッドの表示を整理するために使っている[[Smalltalk#ファイル用構文|クラスカテゴリーとメソッドカテゴリー]](プロトコルとも言う)をそのまま取り込んだ。
クラスの実装を関連するメソッド群毎に別々の場所に分割して記述することを可能とする目的で作られた。
このほか、カテゴリに宣言したメソッドが実行時にカテゴリがロードされたタイミングでクラスへ追加される、という性質を応用して、ソースコードを直接修正できないクラスに対してサブクラスを定義せずにメソッドを追加する、といった用途や、Informalプロトコルの定義等にも用いられる。
カテゴリメソッドで既存のメソッドをオーバーライドすることも可能であるが、推奨されていない。
カテゴリの例.
@interface NSObject (BetterHash)
- (unsigned)hash;
@end
@implementation NSObject (BetterHash)
// 子孫クラスのうち、独自のオーバーライドのない-hashは全てこの実装に置き換わる
- (unsigned)hash
 return better_hash_function(self);
@end
メモリ管理.
初期のObjective-CプログラムはC同様単純な割当と解放を行なっていたが、現在は標準APIライブラリに実装された[[参照カウント]]方式のAutorelease poolを利用するのが標準的である。参照カウント方式ではあるが[[ガベージコレクション]]とは異なり、半自動で行なわれる。
方法としてはNSAutoreleasePoolクラスをインスタンス化し、ここに解放されるべきオブジェクトを、codice_19メッセージを用いて登録する。登録した全てのオブジェクトが不要になったらcodice_20メッセージでNSAutoreleasePoolのインスタンスを解放する。すると登録されていたオブジェクトもすべて一斉に解放されるというものである。
ほかにもオブジェクト(仮にcodice_21とする)のイニシャライザ(初期化メソッド)を呼び出すと、その時点で自分をcodice_19するオブジェクトを定義できる。そのようなオブジェクトをインスタンス化したユーザは、codice_21に対して明示的にcodice_19せずとも、NSAutoreleasePoolのインスタンスをcodice_20するだけでcodice_21を解放できることになる。例としてNSStringクラスがある。codice_27で初期化するとcodice_19された状態になる。
手動管理の場合.
int count = 0;
// オブジェクトのインスタンス化
// これら2つは自動的に参照カウントが1になる
id objFoo = [[Foo alloc] init];
id objBar = [[Bar alloc] init];
id baz = objFoo; // Fooを間接参照
id qux = objBar; // Barを間接参照
[baz retain]; // Fooの参照カウントは2になる
// オブジェクトの解放
[objFoo release]; // objFooは解放されるがFooの参照カウントは1で維持される
[objBar release]; // 変数quxはretainしていないのでBarは破棄される
[baz release]; // Fooが解放される
count = [qux retainCount]; // Barの参照カウントを参照する。Barは解放されているのでエラー
NSAutoreleasePoolの例.
int count = 0;
// NSAutoreleasePoolのインスタンス化
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id objFoo = [[Foo alloc] init];
id objBar = [[Bar alloc] init];
id objBaz = [[Baz alloc] init];
// Autorelease poolに登録
[objFoo autorelease];
[objBar autorelease];
[objBaz autorelease];
// オブジェクトを参照する変数
id qux = objFoo;
id fooBar = objBar;
[qux retain]; // FooのretainCountは2
// Autorelease poolの解放
[pool release];
count = [qux retainCount]; // Fooをretain後オーナーだったobjFooが解放されたので1
count = [fooBar retainCount]; // Barをretainしていないのでエラー
count = [objBaz retainCount]; // ほかの参照がなかったので解放済み。エラー
count = [objBar retainCount]; // fooBarがretainしていなかったのでエラー
オーナー(所有者)とは、あるオブジェクトのインスタンスをcodice_29またはcodice_19したオブジェクトないしは変数のことで、上の例で、codice_31をcodice_20する直前ではcodice_33で始まる変数とcodice_34が該当する。
OPENSTEPライブラリは、イベントサイクル単位でAutorelease poolと呼ばれる暗黙の参照元を持っており、オブジェクトをここに登録することでイベント終了時には自動で解放されるオブジェクトを実現している。Macに移植後もNSApplicationクラスに実装されているが、オブジェクトの登録も不要となっている。前述のNSAutoreleasePoolは、NSApplicationクラスが不要なときでも自動解放ができるように用意されたものといえる。
GNU版ランタイム及び、Mac向けのApple版ランタイム(Objective-C 2.0以降)ではガベージコレクションも利用可能だが、iOSに於てはリソースの効率上使用できない。Appleはさらに第三の方式としてARC (Automatic Reference Counting) 方式を開発した。またガベージコレクションは[[OS X El Capitan|OS X 10.11]]を最後に廃止されており、それ以降Apple系ではARCが主流となっている。
自動参照カウント (ARC).
自動参照カウントは内部的にはcodice_29/codice_20/codice_19と同様のメカニズムで動作するが、コンパイル時にメソッドの命名ルール等を見て自動的にcodice_29/codice_20相当のコードを挿入する方式である。これにより、自動参照カウントでは明示的なcodice_29/codice_20がそもそも不可能になる。管理周りのコードの削減に加え、codice_19管理の実行効率が向上するため、旧方式のプログラムを自動参照カウントに切り替えるだけでもパフォーマンスがいくぶん向上する。
その他.
メタ言語的メカニズム.
オブジェクトシステムはを行い、オブジェクトシステム自体がCで書かれていることに加え、C哲学である「プログラマにできることを制限しない」を良くも悪くも受け継いでいるため、Objective-Cにはさまざまな超言語的技法が存在している。これらの機能は非常に強力であるため乱用を避けるべきだが、この柔軟性こそがObjective-Cの魅力と評する向きもある。
Objective-C++.
Objective-CとC++が混在したもの。両者はCからの拡張部分がほぼ干渉しないため、お互いをただのポインタ値と見なすことで表記が混在できる。したがってクラスシステムの互換性はなく、単純なObjective-C & C++になる。拡張子は.mm。
[[サブルーチン|関数]]やObjective-C[[メソッド (計算機科学)|メソッド]]の内部では、Objective-CとC++両方の機能を任意に組み合わせて利用することができる。例えば、Objective-Cオブジェクトの寿命を管理する[[スマートポインタ]]を、C++の機能を用いて作成するようなことが可能である。他方、[[クラス (コンピュータ)|クラス]]の階層はObjective-CとC++で完全に分かれており、一方が他方を[[継承 (プログラミング)|継承]]することは全く不可能である。また、伝統的なObjective-Cの[[例外処理]]とC++のそれは互換性がなく、プログラマが両者を逐一捕捉・変換しなければ、[[メモリリーク]]や[[クラッシュ (コンピュータ)|クラッシュ]]につながる。
主な用途はC++のライブラリをObjective-Cからアクセスするためのラッパー記述で、実例としてAppleの[[WebKit]]（[[KHTML]]ベース）などがある。コンパイル速度が非常に遅くなることもあって積極的に用いられることは少ない。
言語ブリッジ.
上述のように、Objective-Cランタイムシステムの実体はC言語関数群そのものである。このライブラリの内部でリフレクションやメッセージ送信の機構が全て閉じているため、これらに対するラッパーを用意することで、外部言語からシステムの完全制御が可能になる。
現在言語ブリッジが確立している言語には、、[[Python]]（[[PyObjC]]）、[[Ruby]]（）などがある。
Objective-C 2.0.
Appleは[[Mac OS X v10.5]]においてObjective-C 2.0という名称で言語仕様の変更を行った。
参考文献.
Objective-Cに関する最初の本であり、Objective-Cを利用したオブジェクト指向システム開発に関する本。
この本はObjective-CのNeXTSTEPでの実装について記述している。NeXTSTEPが明確なターゲットだが、Objective-Cを学習するためのよい入門書となる。
多くの実例とともに、Stepstone版とNeXT版のObjective-Cについて、両者の違いを含めて論じている。
Objective-C、C++、Smalltalk、[[Object Pascal]]、Javaを比較しながら、オブジェクト指向プログラミングの話題を紹介している。
外部リンク.
[[Category:オブジェクト指向言語]]
[[Category:プログラミング言語]]
[[Category:MacOS]]
[[Category:iOS]]