5

実行時にメソッドを取得し、そのデータ構造を使用してその実装を呼び出そうとしています。明確にするために、これは学習目的であり、実用的な理由ではありません。だからここに私のコードがあります。

#import <Foundation/Foundation.h>
#import <stdio.h>

#import <objc/runtime.h>

@interface Test : NSObject 
-(void)method;
@end

@implementation Test

-(void)method {
    puts("this is a method");
}

@end 

int main(int argc, char *argv[]) {

    struct objc_method *t = (struct objc_method*) class_getInstanceMethod([Test class], @selector(method));
    Test *ztest = [Test new];

    (t->method_imp)(ztest, t->method_name);

    [ztest release];
    return 0;
}

の定義struct objc_methodは以下の通り(objc/runtime.hで定義)

typedef struct objc_method *Method;

....

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

ただし、コードをコンパイルしようとすると、このエラーが発生します。

error: dereferencing pointer to incomplete type

しかし、これを (objc_method を明示的に宣言するために) コードに追加すると、期待どおりに機能します。

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
};

typedef struct objc_method* Method;

objc/runtime.h からインポートしたときではなく、この構造を明示的に宣言したときにコードが機能する理由を誰かに説明してもらえますか? OBJC2_UNAVAILABLE と何か関係がありますか? その定義が見つかりませんが、私の環境では定義されています。

編集:

OBJC2_UNAVAILABLEgcc -E code.m -o out.mが何に置き換えられるかを調べてみたところ、私の環境では OBJC2_UNAVAILABLE が __attribute__((unavailable)) として定義されていることがわかりました。Methodこの構造が「利用できない」場合、誰かがそれが何を意味し、なぜまだ機能するのかを説明できますか?

4

2 に答える 2

6

私はobjcランタイムヘッダーをよく見て、問題が何であるか、そしてそれを修正する方法を見つけました:)

したがって、構造の透過的な定義を含むファイルの領域を見ると、それが次の本体にあることがわかります。

#if !__OBJC2__

...

#endif

これは定義されているので、私たちが参照する構造は実際には前方宣言されて不透明である(したがって不完全である)ことを意味します。

代わりに、これらのメンバーにアクセスするために提供されている関数を使用する必要があります。

IMP method_getImplementation(Method method);
SEL method_getName(Method method);
void method_getReturnType(Method method, char *dst, size_t dst_len);

等。

アクセサメソッドの完全なリストとその他の多くの機能については、ランタイムリファレンスガイドを参照してください。

それが役に立てば幸い!

于 2012-08-02T05:43:25.877 に答える
5

そのフィールドは以前に定義されていましたが、ObjC-2 では不透明な型です。代わりにランタイムを使用し、自分でフィールドを定義しないでください。

int main(int argc, char *argv[]) {

    Method t = class_getInstanceMethod([Test class], @selector(method));
    Test * ztest = [Test new];

    IMP imp = method_getImplementation(t);

    typedef void (*fn)(id,SEL);
    fn f = (fn)imp;
    f(ztest,@selector(method));

    [ztest release];
    return 0;
}
于 2012-08-02T05:51:13.400 に答える