10

NSInvocation特定の呼び出しを行う方法を探していIMPます。デフォルトでは、IMP見つけることができる「最も低い」もの(つまり、最近オーバーライドされたバージョン)を呼び出しますIMPが、継承チェーンの上位から呼び出す方法を探しています。IMP呼び出したいものは動的に決定されます。それ以外の場合は、キーワードなどを使用できますsuper

私の考えは、-forwardInvocation:メカニズムを使用してメッセージをキャプチャし (簡単で既に機能している)、それを変更して、実装でも最も遠い子孫の実装でもIMPないメソッドに移動することでした。super(難しい)

私が見つけた唯一のものはAspectObjectiveCですが、これには libffi が必要であるため、iOS とは互換性がありません。理想的には、これをクロスプラットフォームにしたいと思います。

何か案は?

免責事項:私はちょうど実験しています


@bbum のトランポリン機能のアイデアを試す

それで、私は物事をほとんどセットアップしたと思います。を介して正しく追加される次のトランポリンがclass_addMethod()あり、入力されます。

id dd_trampolineFunction(id self, SEL _cmd, ...) {
    IMP imp = [self retrieveTheProperIMP];
    self = [self retrieveTheProperSelfObject];
    asm(
        "jmp %0\n"
        :
        : "r" (imp)
        );
    return nil; //to shut up the compiler
}

JMPの前に適切な自己と適切なIMPの両方が正しいことを確認し、_cmdパラメーターも適切に入っています。(つまり、このメソッドを正しく追加しました)。

しかし、何かが起こっています。nilself_cmd. また、EXC_BAD_ACCESS で何もないところにクラッシュすることもあります。アイデア?(アセンブリで何かをしたのは久しぶりです...) x86_64でこれをテストしています。

4

7 に答える 7

4

参考のために、事実のずっと後に追加されました:

プライベート API でそれを行うことができます。このカテゴリを便利な場所に置きます。

@interface NSInvocation (naughty)
-(void)invokeUsingIMP:(IMP)imp;
@end

ほら、それはあなたが期待することを正確に行います。私は、Mike Ash の古いブログ記事の 1 つからこの宝石を掘り起こしました。

このようなプライベート API のトリックは、研究や社内コードに最適です。アプリストアにバインドされたビルドから削除することを忘れないでください.

于 2013-02-05T22:24:30.527 に答える
4

NSInvocation は、メッセージ送信の単なるオブジェクト表現です。そのため、通常のメッセージ送信よりも特定の IMP を呼び出すことはできません。呼び出しで特定の IMP を呼び出すには、IMP 呼び出しルーチンを通過するカスタム NSInvocation クラスを作成するか、動作を実装するトランポリンを作成してから、次を表す呼び出しを作成する必要があります。トランポリンへのメッセージ (つまり、基本的に NSInvocation を使用することはほとんどありません)。

于 2011-02-19T06:17:41.283 に答える
3

テストされていないアイデア:

object_setClass()必要なものを強制的に選択するために使用できますIMPか?つまり…</p>

- (void)forwardInvocation:(NSInvocation *)invocation {
    id target = [invocation target];
    Class targetClass = classWithTheImpIWant();
    Class originalClass = objc_setClass(target, targetClass);
    [invocation invoke];
    objc_setClass(target, originalClass);
}
于 2011-02-19T06:44:56.513 に答える
3

すでに IMP を持っていることを考えると、その IMP へのメソッド呼び出しの非常に生の転送を行う方法が必要なだけです。また、NSInvocation のようなソリューションを使用する意思がある場合は、同様のプロキシ クラスを作成することもできます。

これに直面した場合は、呼び出される IMP とターゲット オブジェクト (selfパラメーターを設定する必要があります) を含む単純なプロキシ クラスを作成します。次に、最初の引数を受け取り、それがプロキシ クラスのインスタンスであると想定し、self. .

トランポリンを手にしたら、そのトランポリンを、特定の IMP に転送したいプロキシ クラスの任意のセレクターの IMP として追加します。

このようなあらゆる種類の汎用メカニズムを実現するための鍵は、スタック フレームの書き換えに関係することを避けることです。C ABI を避けます。議論を動かさないようにします。

于 2011-02-19T08:10:03.347 に答える
2

あなたの最良の選択は libffi を使用することだと思います。https://github.com/landonf/libffi-iosで iOS へのポートを見ましたか? ポートは試していませんが、Mac で任意の引数を指定して IMP を呼び出すことに成功しました。

JSCocoa https://github.com/parmanoir/jscocoaffi_cifを見てください。これには、から構造を準備するのに役立つコードがMethod含まれており、iOS でコンパイルする必要があるバージョンの libffi も含まれています。(どちらもテストしていません)

于 2011-02-19T11:23:24.763 に答える