0

私は多くのクラスを持つプロジェクトを持っています。実行時に各セレクターの呼び出しを (stderr などに) ログに記録したいと考えています。
私の主な要件は、既存のコードを変更することではないため、各呼び出しの開始時に関数のパラメーターをログに記録することはできません。

プログラムの実行中に何らかのメソッドが呼び出された場合、たとえば

@implementation Class1

// ...

- (int)someFunc:(Class2*) a andClass3:(Class3*)b
{

}

// ...

@end 

私はそれを次のようなものに置き換えたい:

- (int)someFuncWrapper:(Class2*) a andClass3:(Class3*)b
{
     NSLog(@"- (int)someFuncWrapper:a andClass3:b <= a=%@, ab=%@", a, b);
     return [someFunc: a andClass3:b];
}

出来ますか?

メソッドのスウィズリング、KVO、フォワードメッセージングについて読んだことがあります。

メソッドのスウィズリングを使用した現在のアプローチでは、無限の再帰が発生します。

- (int)funcToSwizzle:(int)a andB:(int)b
{
    int r = a+b;
    NSLog(@"funcToSwizzle: %d", r);
    return r;
}

- (void)doSimpleSwizzling
{
    NSLog(@"r1 = %d", [self funcToSwizzle:10 andB:20]);

    Class curClass = NSClassFromString(@"HPTracer");

    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList( curClass, &methodCount);

    for (int i=0; i<methodCount; ++i)
    {
        SEL originalSelector = method_getName(methods[i]);
        if ( strcmp("funcToSwizzle:andB:", sel_getName(originalSelector)) == 0 )
        {
            Method m1 = class_getInstanceMethod(curClass, originalSelector);

            id block3 = ^(id self, int a, int b) {
                NSLog(@"My block: %d", a*b);
                // get current implementation of "funcToSwizzle".
                // copy it. store that "IMP"/"void *" etc
                return [self funcToSwizzle:a andB:b];
            };

            IMP imp3 = imp_implementationWithBlock(block3);
            method_setImplementation(m1, imp3);
        }
    }

    NSLog(@"r2 = %d", [self funcToSwizzle:10 andB:20]);
}

block3残念ながら、実行時に 1 つまたはいくつかのメソッドを生成することは不可能です。ありますNSSelectorFromStringが、ありませんImplementationFromString

UPD
DTrace util を調べましたが、非常に強力なようですが、私のニーズには合いません。Mac OS で SIP を無効にする必要があり、iOS では不可能か、ジェイルブレイクされたデバイスでは可能です。

メソッドのインターセプトに必要なのは、デバッグとプロダクション ビルド モードの両方で安定したカスタム「フレームワーク」を作成することです。

4

0 に答える 0