IMP
私が理解している限り、Objective-Cの型は関数ポインターを表します。IMP
ブロックポインタから作成する方法はありますか? アイデアをありがとう。
2 に答える
これが書かれて以来、ブロックを直接 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_setImplementation
and like)
警告:
これは StackOverflow に入力されました。実際のコードは似ていますが、わずかに異なる可能性があります。
[implementingBlock コピー] は重要です。ブロックはスタック上でライフを開始します (通常)
マイク・アッシュは、ランドン・フラーの助けを借りて、より難しいiOSを含む一般的なケースでこれを解決したと思います。彼は、ブロックを関数ポインターに変換するクラスをgithubに持っています。
また、ココアアンバウンドに関する発表といくつかの興味深いフォローアップディスカッションを行うこともできます。
更新:そして今、imp_implementationWithBlock()
上記のようになっています。