クラス


HOME > TIPS > Cocoa Programming Tips 1001 > Objective-C > クラス

クラス

Objective-C - クラス

Class とは

Keywords: Class

Objective-C で、オブジェクトのクラスを表すのは Class 型。で、結局のところ、この Class 型って何なの?

順に追っていこう。まず、Class 型の定義は /usr/include/objc/obj.c にある。

/usr/include/objc/objc.h

typedef struct objc_class *Class;

つまり、Class 型は、構造体 objc_class のポインタだ。構造体 objc_class の定義は /usr/include/objc/objc-class.h にある。

/usr/include/objc/objc-class.h

struct objc_class {
 struct objc_class *isa;
 struct objc_class *super_class;
 const char *name;
 long version;
 long info;
 long instance_size;
 struct objc_ivar_list *ivars;

 struct objc_method_list **methodLists;

 struct objc_cache *cache;
 struct objc_protocol_list *protocols;
};

これが、メモリ上に展開される、クラスの実体になるわけだ。含まれている情報は、

isa
 このクラスの isa ポインタ

super_class
 親クラス

name
 クラスの名前

version
 バージョン

instance_size
 インスタンスの大きさ

ivars
 インスタンス変数のリスト

methodLists
 メソッドリスト(複数)

protocols
 プロトコル

っていう感じだ。これで、Objective-C の実行環境に必要な情報が、ほぼそろうね。





Objective-C - クラス

アプリケーションで使っているクラスをすべて取得する

Keywords: objc_getClassList

あるアプリケーションで、Objective-C runtime が持っているすべてのクラスを取得してみよう。そのための、そのものずばりの関数がある。objc_getClassList() だ。/usr/include/objc/objc-runtime.h に定義がある。

/usr/include/objc/objc-runtime.h

OBJC_EXPORT int objc_getClassList(
  Class *buffer,
  int bufferLen);

この関数を呼ぶときは、buffer に Class のポインタが入るバッファを、bufferLen にはその大きさを指定するんだ。返り値は、クラスの数が入る。

ヘッダ objc-runtime.h に、この関数の使い方が書いてある。まず、buffer に NULL を指定して呼んでやる。そうすると、返り値として、クラスの数が返ってくるんだ。そうしたら、その大きさだけのメモリを確保して、もう一回呼んでやるんだ。クラスの数が多すぎたら、何回かに分けて呼んでやる。

showAllClasse() (sample)

#import <objc/objc-runtime.h>

void showAllClasses {
 int numClasses = objc_getClassList(NULL, 0);
 int i;
 Class* classes;
 Class* tmp;

 classes = malloc(sizeof(Class) * numClasses);
 objc_getClassList(classes, numClasses);

 tmp = classes;
 for(i = 0; i < numClasses; i++) {
  printf("%s?", (*tmp++)->name);
 }

 free(classes);
}

上のコードが、すべてのクラスにアクセスするサンプルだ。取り出した後に、そいつらの名前を printf() で表示させているよ。




Objective-C - クラス

クラスを階層表示する

Keywords: objc_getClassList

すべてのクラスを取得したので、それを階層表示させてみよう。Class 型、すなわち objc_class 構造体には、super_class という親クラスへのポインタがあるんだ。

/usr/include/objc/objc-class.h

struct objc_class {
 ...
 struct objc_class *super_class;
 ...
};

これをたどっていけば、階層構造を知ることができる。ルートクラスは、これが nil になってるよ。

階層構造を表示する、簡単なアプリケーションを作ってみた。実際に階層を調べるところは、こんな感じになっている。

ClassViewerControll.m (sample)

// Get all classes
classes = malloc(sizeof(Class) * numClasses);
objc_getClassList(classes, numClasses);

tmp = classes;
for(i = 0; i < numClasses; i++) {
 // Get class name
 classNameStr = [NSString stringWithCString:(*tmp)->name];
 [_classNameArray addObject:classNameStr];

 // Get super class name
 if((*tmp)->super_class != nil) {
   NSMutableArray*  array;

 superNameStr = [NSString
   stringWithCString:(*tmp)->super_class->name];

 array = [_classNameHierDict objectForKey:superNameStr];
 if(array == nil) {
   // Create new array
   array = [NSMutableArray array];
   [_classNameHierDict setObject:array forKey:superNameStr];
  }

  [array addObject:classNameStr];
 }
 else {
   // This class should be root
   [_classNameRootArray addObject:classNameStr];
 }

 tmp++;
}

free(classes);


最初に、すべてのクラスを取得する。そして、それを一個ずつ走査していくんだ。まず、そのクラスの名前を調べる。次に、親がいるかどうかを、super_class を見ることによって、調べるんだ。親がいる場合は、その親の名前を key にして、dictionary につっこむ。いない場合は、これはルートクラスなので、それ専用の array に入れてるんだ。

これで、root の array からたどっていけば、階層構造を知ることができるんだ。試しに作ってみたアプリケーションの実行結果は、下のような感じ。

classViewer.jpg


■サンプルダウンロード:
ClassViewer.tar