9

SIMBL を使用してプログラムの動作を変更しようとしています (ソースがありません)。クラスダンプを使用したところ、インスタンスメソッドをオーバーライドする必要があることがわかりました

このメソッドは、controller というクラスにあります。私がする必要があるのは、引数 arg1 を取得することだけです。多分 NSLog するか、通知を投稿してください... Objective-C のメソッドのスウィズリングについて読みましたが、どのように使用できますか?. コースを持っていないクラス MessageController を参照する必要があります。

ありがとう!

4

2 に答える 2

35

NSLog を実行した後、元の実装を呼び出す必要があると思います。そうでない場合は、クラスのカテゴリを使用してメソッドをオーバーライドできる場合があります。

メソッドをスウィズルするには、まず代替メソッドが必要です。私は通常、ターゲットクラスのカテゴリに次のようなものを入れます:

- (void)replacementReceiveMessage:(const struct BInstantMessage *)arg1 {
    NSLog(@"arg1 is %@", arg1);
    [self replacementReceiveMessage:arg1];
}

これは自分自身を再帰的に呼び出すように見えますが、古いバージョンを呼び出している間、呼び出しはこのメソッドを呼び出し、呼び出しReceiveMessage:はこのメソッドを呼び出します。replacementReceiveMessage:

2 番目のステップは、ランタイム関数を使用して実際にスワップを実行することです。loadカテゴリを使用する利点は、作業を行うためにカテゴリで使用できることです。

+ (void)load {
    SEL originalSelector = @selector(ReceiveMessage:);
    SEL overrideSelector = @selector(replacementReceiveMessage:);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
    if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
            method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

処理する必要がある 2 つのケースがあります。

  • スウィズルしているメソッドが実際にスーパークラスで定義されている場合は、を使用class_addMethodして、の実装をターゲット クラスに追加するReceiveMessage:必要があります。これは、置換実装を使用して行います。次に、スーパークラスの実装class_replaceMethodに置き換えるために使用できるreplacementReceiveMessage:ため、新しいバージョンは古いバージョンを正しく呼び出すことができます。
  • メソッドがターゲット クラスで定義されている場合class_addMethodは失敗しますがmethod_exchangeImplementations、新しいバージョンと古いバージョンを交換するために使用できます。
于 2011-03-20T22:38:26.143 に答える
6

ライブラリjrswizzleがそれを処理します。多くの詳細を正しく設定する必要があるため、自分で行うことはお勧めしません。(jrswizzle の readme で、以前の実装の失敗を文書化した表を参照してください。)

次のようなクラスがあるとします。

@interface Weh : NSObject
-(void)foo;
-(void)bar;
@end

@implementation Weh
-(void)foo {
    NSLog(@"Foo called");
}
-(void)bar {
    NSLog(@"Bar called");
    [self bar];
}
@end

次のように使用できます。

Weh *weh = Weh.new;
[weh foo];
[Weh jr_swizzleMethod:@selector(foo) withMethod:@selector(bar) error:nil];
[weh foo]; 

出力:

Foo called
Bar called
Foo called
于 2013-07-02T19:42:40.357 に答える