メソッドの引数や返り値を調べる

指定したクラスの、実装されているメソッドを列挙する - すぎゃーんメモの、続きのようなもの。
クラスに実装されているメソッドの一覧を取り出すことはできたので、今度は一つ一つのメソッドについての詳細を調べる。
例えばNSIndexPathの中にある"initWithIndexes:length:"というメソッドについて知りたいとき。

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
    unsigned int i;
    size_t buf_size = 256;
    char *buffer = malloc(buf_size);

    // ターゲットのクラス
    Class target_class = [NSIndexPath class];
    // ターゲットのメソッドを取り出す
    SEL sel = @selector(initWithIndexes:length:);
    Method method = class_getInstanceMethod(target_class, sel);

    // 引数を調べる
    NSLog(@"Argument Type");
    unsigned int num = method_getNumberOfArguments(method);
    for (i = 0; i < num; i++) {
        method_getArgumentType(method, i, buffer, buf_size);
        NSLog(@"%d: %s", i, buffer);
    }
    // 返り値を調べる
    NSLog(@"Return Type");
    method_getReturnType(method, buffer, buf_size);
    NSLog(@"%s", buffer);

    // Type Encoding
    NSLog(@"Type Encoding");
    NSLog(@"%s", method_getTypeEncoding(method));
    
    free(buffer);
    [pool release];

    return 0;
}


コンパイルして実行してみると

$ gcc -Wall -framework Foundation hoge.m
$ ./a.out 
2009-04-07 15:28:18.596 a.out[12538:10b] Argument Type
2009-04-07 15:28:18.598 a.out[12538:10b] 0: @
2009-04-07 15:28:18.598 a.out[12538:10b] 1: :
2009-04-07 15:28:18.598 a.out[12538:10b] 2: ^I
2009-04-07 15:28:18.599 a.out[12538:10b] 3: I
2009-04-07 15:28:18.601 a.out[12538:10b] Return Type
2009-04-07 15:28:18.601 a.out[12538:10b] @
2009-04-07 15:28:18.601 a.out[12538:10b] Type Encoding
2009-04-07 15:28:18.602 a.out[12538:10b] @16@0:4^I8I12

引数は4つ出てきているようだ。それぞれの型は以下を参考に照らし合わせる…しかないのかな?
http://developer.apple.com/jp/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_13_section_9.html#//apple_ref/doc/uid/TP30001163-CH9-TPXREF165
メソッドとしては引数2個なんだけど、実際にruntimeの中でobjc_msgSend関数に渡される引数は、第1にレシーバ、第2にセレクタが渡されるので、メソッドとしての引数は3番目以降になる、ということかな。

id objc_msgSend(id theReceiver, SEL theSelector, ...)

http://developer.apple.com/jp/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_8_section_2.html


というわけで、"unsigned int *"と"unsigned int"がこのメソッドに渡され、"オブジェクト"が返される、ということが読み取れる。
ドキュメントで確認してみると、その定義通りですね。


最後のmethod_getTypeEncoding関数から得られる文字列は返り値と引数を同時に記述してくれているようだけど、読み方がよくわからない。