|
- 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.tar.gz
|