2012-06-08 8 views
7

このコードはEXC_BAD_ACCESSを返します。なぜですか?なぜこのコードはEXC_BAD_ACCESSを与えますか(IMPを使用)

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

私はIMP、firs try .. no luckを使い始めています。私はなぜエラーが出るのか分かりません。過去には、EXC_BAD_ACCESSを取得したときにメッセージがコンソールに表示されましたが、今回はエラー行が強調表示されています。

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

おかげでみんな

+0

私は再現できません。これを新しいプロジェクトに入れると、まだエラーが出ますか? – Chuck

+0

うん、私が見つけたもの... ARCが問題です。 ARCを有効にして新しいiOSプロジェクトを作成してみてください。その後、コードをどこかにコピー&ペーストしてください(私はアプリケーションdidFinishLaunchingWithOptionsに入れます:) – subzero

答えて

20

関数ポインタを適切にキャストする必要があります。または、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を使うべきではありません。大きな問題を引き起こす他の場所は、メソッドが構造体を返すかどうか、またはメソッドが浮動小数点パラメーターなどを受け取るかどうかです。

良い習慣:関数ポインター構文が見つかると、常に関数ポインターをキャストまたはtypedefを作成します。 。

+0

ありがとうございました。それは魅力として働いた!質問:浮動小数点パラメータを持つ構造体やメソッドで大きな問題が発生するのはなぜですか?ドキュメントを指すことができれば、私はもっと幸せになれます。私はちょうど興味深い "ランタイム"トピックを見つけました。 – subzero

+1

Cでの関数の呼び出し規約とパラメータの受け渡し方法と関係があります。コンパイラは 'self'と' _cmd'パラメータを過ぎたIMPのパラメータについて何も知らないので、他のパラメータをスタックにプッシュし、呼び出された関数がそれらと何をするべきかを知ることを期待します。しかし、呼び出された関数が浮動小数点を予期していた場合、GPR(ARM用)やその他のfp固有のレジスタではなく、スタックなどでほとんど確実に検索されます。戻り型の場合も構造はポインタとは異なります。 –

1

IMPは、ARCが管理しようとする戻り値の型が "id"であるという問題があります。戻り値の型を無効にするために、関数ポインタをキャストする必要があります(呼び出すメソッドと一致します)。

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"); 
+0

'void(*)(id、SEL、...)'は関数ポインタの型ではありません。 'void(*)(id、SEL、id、id)'です。この特定のケースでは特定のタイプ( 'id')を持つ特定のアーキテクチャでは動作しますが、一般的には間違っています。 – newacct

+0

これは実際に動き出しました。ありがとう。 – Felipe

関連する問題