【コラム】

ダイナミックObjective-C

3 Cocoa実現の肝 - クラスとそのメソッドの調査方法をチェック

    木下誠  [2005/08/24]

    前回は、すべてのオブジェクトはid型になることを説明したが、今回はそのオブジェクトの性質を調べる方法を説明しよう。今回説明する調査のポイントは次の2点となる。

    • そのオブジェクトはどのクラスに属しているのか?
    • どのメソッドに対応できるのか?
    だ。早速、説明しよう。

    クラスオブジェクト

    まず、オブジェクトのクラスを調べる方法を説明しよう。すべてのオブジェクトは自分のクラスに関する情報をメタ情報として持っており、これをクラスオブジェクトという形で取得できる。

    クラスオブジェクトは、classというメソッドを使ってオブジェクトから取得することができる。型は、id型を使っても良いし、クラスオブジェクトのための型Classを使うこともできる。例えば、あるメソッドにid型のオブジェクトが渡された場合、次のようなコードでクラスオブジェクトを取得可能だ。

    - (void)method:(id)object
    {
      // 引数objectからクラスオブジェクトclsを取得する
      Class cls;
      cls = [object class];
      ...

    クラスオブジェクトはクラスからも直接取得できる。この場合、同名のclassというクラスメソッドを利用する。次のコードは、NSStringクラスからクラスオブジェクトを取得する例である。

    // NSStringのクラスオブジェクトを取得
    Class stringCls;
    stringCls = [NSString class];

    また、文字列から取得することもできる。これには、NSClassFromStringという関数を使う。この関数を使うことで、コンパイル時に存在しないクラスのクラスオブジェクトを得ることが可能となる。また、指定したクラスが実行中のランタイムに存在しない場合、不正を表すnilが返ってくるので、クラスの存在をチェックすることもできる。

    // MyGreatClassのクラスオブジェクトを取得
    Class myClass;
    myClass = NSClassFromString(@"MyGreatClass");

    クラスの調査

    さきほど説明したクラスオブジェクトを使うと、あるオブジェクトがどのクラスに属しているかを調べることができる。これには、isKindOfClass:と、isMemberOfClass:というメソッドを使う。どちらも、ルートクラスであるNSObjectのメソッドなので、すべてのオブジェクトで利用できる。

    isKindOfClass:は、そのオブジェクトが指定したクラスか、そこから継承されたクラスの場合、YESを返す。isMemberOfClass:は、継承されたクラスは無視し、まさにそのクラスだった場合のみ、YESを返す。サンプルを示そう。メソッドの引数objectが、NSStringクラスに属するかどうかは、次のようなコードで調べることができる。

    - (void)method:(id)object
    {
      // objectがNSStringクラスかどうかを確認
      if ([object isKindOfClass:[NSString class]]) {
        // NSStringクラスの場合
        ...
      }

    他にも、クラスオブジェクトから文字列を取得して調査する方法もある。クラスオブジェクトのdescriptionメソッドか、NSStringFromClass関数で、クラス名を文字列として得ることができるので、これでもチェックできる。

    メソッドの調査

    次に、オブジェクトの持つメソッドを調べてみよう。オブジェクトに指定したメソッドが実装されているかどうか調べることができるのだが、これにはセレクタと呼ばれるものを使う。

    セレクタは、メソッドを指定するために使われ、@selector指示子にメソッド名を指定することで得ることが可能だ。また、NSSelectorFromStringという関数を使って、文字列から取得することもできる。セレクタには、SELという型が使われる。次の例では、name、setName:というメソッドのためのセレクタを作っている。

    // セレクタの取得
    SEL nameSel, setNameSel;
    nameSel = @selector(name);
    setNameSel = NSSelectorFromString(@"setName:");

    このセレクタを使うことで、メソッドが実装されているかどうかを調査できる。それには、respondsToSelector:というメソッドを使う。

    - (void)method:(id)object
    {
      // objectがメソッドnameを実装しているかどうかを確認
      if ([object respondsToSelectlr:@selector(name)]) {
        ...
      }

    上のようなコードで、そのオブジェクトがnameメソッドを実装しているどうか確認できるので、実際にメソッドの呼び出しを行える。呼び出しは直接行ってもいいし、セレクタを指定して呼び出すこともできる。それには、performSelector:というメソッドを使う。

        // メソッドを呼び出す
        [object performSelector:@selector(name)];
        ...

    これが、id型のオブジェクトを調査する方法だ。コンパイルの時点では、どんなオブジェクトがくるか分からないとしても、このように実行時にメソッドの存在を確認して呼び出すことができる。

    だが、これだけだったら、コンパイル時に厳密に型をチェックして、そのメソッドを持っているオブジェクトが来ることを保証した方がいいのではないだろうか? ところが違うのである。Cocoaはまさにこの仕組みを直接的に利用することで、柔軟なアプリケーションフレームワークを実現しているのである。次回は、いよいよその例を紹介しよう。

    新着記事

    特設サイトの情報

      人気記事

      一覧

        イチオシ記事

        新着記事

        特別企画

        マイナビニュースマガジン