2012年1月20日金曜日

isaって何?

デバッグをしていると、よくisaという変数を目にすることがあります。
isaは、NSObjectが持っている構造体で、スーパークラスへのポインタや、メソッドの情報を保持しています。

例えば、NSMutableStringはNSStringクラスを継承したクラスですが、NSMutableStringのisa変数の中にNSStringへのポインタを保持しています。

また、NSMutableStringは「stringByAppendingString:」というメソッドを持っていますが、このメソッドの情報を以下の様にNSMutableStringのisa変数に格納しています。

セレクタ メソッド名の文字列
 22   stringByAppendingString:
 33   メソッドA
 44   メソッドB
 ・     ・
 ・     ・
 ・     ・

上の例のセレクタは説明の為適当な値です。また、セレクタはchar*型ですが、実際にはint型の数値が入ります。
Objective-Cのコンパイラは、メソッドの呼び出しを以下の様にC言語のコードに展開します。

[objA stringByAppendingString:objB];
  ↓
objc_msgSend(objA, 22, objB);

「objc_msgSend」関数は、objAにあるセレクタ22に対してobjBを送信してくれるC言語の関数です。
objc_msgSend関数はobjAの中にあるisa変数を参照して、指定されたセレクタ(22)を検索します。そしてそこにあったメソッドにobjBを渡すとともに呼び出してくれます。
ここで該当するセレクタがisaの中に見つからなかった場合は、スーパークラスであるNSStringのポインタを取得し、NSStringのisaに対して同様の処理を行います。
NSStringでも見つからなければ更にその継承元・・という風に辿っていき、最終的にNSObjectでも見つからなければ例外を発生させるという流れになります。

このような処理を行うことで、Objective-Cではプログラム実行時に動的にメソッドを入れ替えることがし易くなっているのです。

ただし、C言語のように直にポインタを呼び出すとかではないので動作は遅くなるはずです。また、C++言語と比べてもObjective-Cは検索処理などが行わる為、動作はかなり遅くなるはずです。(C++言語はクラスメソッドのジャンプテーブルを参照するのでC言語より数ステップ程度動作は遅くなります。)
多分ですが、メソッド呼び出しだけを見る限りC言語よりも数十倍〜数百倍は遅くなっているはずです。(遅さを補っても余りある利便性があるということです。)