7

このコードで EXC_BAD_ACCESS が表示されるのはなぜですか?

NSMutableDictionary  *d = [[NSMutableDictionary alloc] init];
IMP imp= [d methodForSelector:@selector(setObject:forKey:) ];
imp(d,  @selector( setObject:forKey:), @"obj", @"key");

私は IMP を使い始めたばかりです。エラーが発生する理由もわかりません..以前、EXC_BAD_ACCESSを取得したときに、コンソールにメッセージが出力されましたが、今回はエラー行が強調表示されています。

いくつかのメモ: ARC が有効、XCode 4.3.2、プロジェクトはデフォルトの言語/コンパイラとして Objective-C++ を使用、このコードはプロジェクトの最初にある

みんなありがとう

4

2 に答える 2

21

関数ポインターを適切にキャストする必要があります。そうしないと、ARC が何をすべきかを認識できません。IMP は、id、セレクター、およびその他の未定義の引数の可変数を取り、id を返す汎用関数ポインターです。呼び出そうとしているメソッドの実装は、id、セレクター、それに続く正確に 2 つの id パラメーターを取り、void 戻り値の型を持ちます。次のコードに変更することで修正できます。

NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
void (*imp)(id, SEL, id, id) = (void(*)(id,SEL,id,id))[dict methodForSelector:@selector(setObject:forKey:)];
if( imp ) imp(dict, @selector(setObject:forKey:), @"obj", @"key");

関数ポインターを逆参照する前に、実際に関数ポインターを取得したことを常に確認する必要があります。これもクラッシュするためです。上記のコードは、ARC 環境でも機能します。また、ARC を使用していない場合でも、IMP ではなく、常に関数ポインターを実際のプロトタイプにキャストする必要があります。IMP は絶対に使用しないでください。大きな問題を引き起こす他の場所は、メソッドが構造体を返す場合、またはメソッドが浮動小数点パラメーターを受け取る場合などです。

良い習慣: 関数ポインターの構文が不快な場合は、常に関数ポインターをキャストするか、それらの型定義を作成します。

于 2012-06-08T17:26:45.373 に答える
1

問題は、IMP が ARC が管理しようとする「id」の戻り値の型を持っていることです。関数ポインターをキャストして、戻り値の型が void になるようにする必要があります (呼び出しているメソッドと一致します)。

    NSMutableDictionary  *d = [[NSMutableDictionary alloc] init];
    IMP imp= [d methodForSelector: @selector(setObject:forKey:)];
    void (*func)(__strong id,SEL,...) = (void (*)(__strong id, SEL, ...))imp;
    func( d,  @selector(setObject:forKey:), @"obj", @"key" );
于 2012-06-08T17:36:24.340 に答える