【コラム】

ダイナミックObjective-C

30 ランタイムAPIでさらに動的に(4) - インスタンス変数の定義を調査

    木下誠  [2006/03/29]

    前回までは、メソッドを操作するランタイムAPIを紹介してきたので、次は当然インスタンス変数の出番だ。今回は、インスタンス変数を取り扱うための、構造体を紹介しよう。

    インスタンス変数の定義の取得

    Objective-Cのクラス定義には、既に述べたようにメソッドの定義が含まれていて、さらにインスタンス変数の定義も含まれている。objc_class構造体に含まれている、instance_sizeとivarsが、それだ。

    objc-class.h

    struct objc_class {
        ……
        long instance_size;
        struct objc_ivar_list *ivars;
        ……
    };

    instance_sizeは、このクラスが持つインスタンス変数の合計サイズになる。言い換えれば、このクラスのインスタンスを作成したときに、確保されるメモリの大きさ、という訳だ。ivarsの方が、インスタンス変数の定義になる。この変数は、objc_ivar_list構造体へのポインタになる。この構造体の定義は、次の通りだ。

    objc-class.h

    struct objc_ivar_list {
        int ivar_count;
        struct objc_ivar ivar_list[1];
    };

    名前の通り、objc_ivarという構造体の配列を管理するためのものだ。ivar_countは配列の数、objc_ivarが配列になる。さて、ここまでくればもう感付いている方もいると思うが、このobjc_ivarがインスタンス変数の定義となる構造体である。その定義は、次の通りだ。

    objc-class.h

    struct objc_ivar {
        char *ivar_name;
        char *ivar_type;
        int ivar_offset;
    };

    この構造体には、3つのフィールドがある。1つ目のivar_nameは、インスタンス変数の名前になる。2つ目のivar_typeは、変数の型だ。この型は、メソッドの型と同じ形にエンコーディングされている。型のエンコーディングについては、本連載の第20回を参考にしてほしい。そして、3つ目のivar_offsetは、この変数がメモリ内部でどこに配置されるかを表している。インスタンス変数のために確保したメモリの、先頭からのオフセットになる。

    また、この構造体のポインタを表すための型も定義されている。Ivarという名前の型だ。

    objc-class.h

    typedef struct objc_ivar *Ivar;

    実際のコードでは、こちらを使うことも多いだろう。

    インスタンス変数の名前の表示

    では、このIvarを利用して、クラス定義からインスタンス変数の定義を抜き出すコードを紹介しよう。次のコードでは、すべてのインスタンス変数の名前を表示している。

    objc-class.h

    void showInstanceVariables(Class cls)
    {
        // ivarsが存在するかどうかを確認する
        if (!cls->ivars) {
            NSLog(@"cls->ivars is NULL");
            return;
        }
        
        // インスタンス変数の数を表示する
        NSLog(@"count %d", cls->ivars->ivar_count);
        
        // すべてのインスタンス変数の名前を表示する
        int i;
        for (i = 0; i < cls->ivars->ivar_count; i++) {
            // Ivarを取得する
            Ivar    ivar;
            ivar = cls->ivars->ivar_list + i;
            
            // 名前を表示する
            NSLog(@"%s", ivar->ivar_name);
        }
    }

    まず始めに、Class型の変数に、ivarsが存在しているかどうかを確認している。インスタンス変数定義が無い場合、このフィールドはNULLになっているので、注意が必要だ。

    次に、objc_ivar_list構造体の、ivar_countの値を表示している。これが、インスタンス変数の定義の数になる。そして、forループを回して、Ivarを取り出している。Ivarからは、ivar_nameにアクセスして、インスタンス変数の名前を調べることができる、という訳だ。

    この方法で調査できるのは、指定したクラスに含まれるインスタンス変数だけだ、ということにも注意しておこう。つまり、親クラスのインスタンス変数の名前は表示されない。それらを表示するには、superclassの定義を調査することが必要になる。

    次回は、このIvarを使って、インスタンス変数の値にアクセスする方法を説明しよう。

    新着記事

    特設サイトの情報

      求人情報

      人気記事

      一覧

      イチオシ記事

      新着記事

      特別企画

      転職ノウハウ

      あなたの仕事適性診断

      4つの診断で、自分の適性を見つめなおそう!

      Heroes File ~挑戦者たち~

      働くこと・挑戦し続けることへの思いを綴ったインタビュー

      はじめての転職診断

      あなたにピッタリのアドバイスを読むことができます。

      転職Q&A

      転職に必要な情報が収集できます

      スカウト転職する

      企業からアプローチのメッセージが届きます。

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