20

IMP私が理解している限り、Objective-Cの型は関数ポインターを表します。IMPブロックポインタから作成する方法はありますか? アイデアをありがとう。

4

2 に答える 2

27

これが書かれて以来、ブロックを直接 IMP に変換できるようにする API が iOS と Mac OS X に存在するようになりました。API (imp_implementationWithBlock()) について説明したブログ記事を書きました。


ブロックは事実上、ビットのメタデータ、ブロック内に含まれるコードへの参照、およびブロック内でキャプチャされた const コピーされたデータのコピーを含む構造です。

したがって、いいえ、IMPとブロック参照の間で直接マップする方法はありません。

ブロックへの呼び出しがコンパイルされると、コンパイラはスタック フレームを設定するトランポリンを出力し、ブロック内の実行可能コードにジャンプします。

ただし、できることは、そのトランポリンのように機能する IMP を作成することです。以下では、呼び出される引数と戻り値のセットごとに 1 つの特定の IMP が必要になります。これをジェネリックにする必要がある場合は、アセンブリを使用する必要があります。

このために、クラスのインスタンスごとに一意のブロック インスタンスを設定しています。すべてのインスタンスで機能するジェネリック ブロックが必要な場合は、SELクラスごとに -> ブロックのハッシュを作成します。

(1) 関連付けられた参照メカニズムを使用して、IMP として機能するようにブロックを関連付けます。何かのようなもの:

void (^implementingBlock)(id s, SEL _c, int v) = ^(id s, SEL _c, int v) {
     // do something here
}

objc_setAssociatedObject(obj, SELToImp, [implementingBlock copy]));

(2) 次のようなトランポリン IMP を実装します。

void void_id_sel_intTramp(id self, SEL _cmd, int value) {
    int (^block)(id s, SEL _c, int v) = objc_getAssociatedObject(self, _cmd);
    block(self, _cmd, value);
}

(3) Objective-C ランタイムの API を介して任意のセレクターに上記のトランポリンを詰め込みます (see method_setImplementationand like)

警告:

  • これは StackOverflow に入力されました。実際のコードは似ていますが、わずかに異なる可能性があります。

  • [implementingBlock コピー] は重要です。ブロックはスタック上でライフを開始します (通常)

于 2009-11-29T23:18:02.227 に答える
10

マイク・アッシュは、ランドン・フラーの助けを借りて、より難しいiOSを含む一般的なケースでこれを解決したと思います。彼は、ブロックを関数ポインターに変換するクラスをgithubに持っています。

また、ココアアンバウンドに関する発表といくつかの興味深いフォローアップディスカッションを行うこともできます。

更新:そして今、imp_implementationWithBlock()上記のようになっています。

于 2010-09-25T16:45:57.390 に答える