質問

Objective-Cでメソッド呼び出しをインターセプトできますか?方法は?

編集: Mark Powell の答えは、 -forwardInvocation メソッドという部分的な解決策を提供してくれました。 ただし、ドキュメントには、-forwardInvocationは、対応するメソッドがないオブジェクトにメッセージが送信されたときにのみ呼び出されると記載されています。レシーバーがそのセレクターを持っている場合でも、すべての状況下で呼び出されるメソッドが欲しいです。

役に立ちましたか?

解決

それを行うには、メソッド呼び出しをスウィズルします。すべてのリリースをNSTableViewに取得する場合:

static IMP gOriginalRelease = nil;
static void newNSTableViewRelease(id self, SEL releaseSelector, ...) {
   NSLog(@"Release called on an NSTableView");
   gOriginalRelease(self, releaseSelector);
}


  //Then somewhere do this:
  gOriginalRelease = class_replaceMethod([NSTableView class], @selector(release), newNSTableViewRelease, "v@:");

Objective Cランタイムで詳細を取得できますドキュメント

他のヒント

Objective-Cでのメソッド呼び出しのインターセプト(C呼び出しではなく、Objective-Cであると想定)は、 method swizzling。

と呼ばれる手法で行われます>

こちらを実装する方法の概要を見つけることができます。実際のプロジェクトでメソッドスウィズリングがどのように実装されるかの例については、 OCMock ( Objective-Cの分離フレームワーク)。

Objective-Cでのメッセージの送信は、関数 objc_msgSend(receiver、selector、arguments)またはそのバリアント objc_msgSendSuper の呼び出しに変換されますobjc_msgSend_stret objc_msgSendSuper_stret

これらの関数の実装を変更できる場合、任意のメッセージを傍受できます。残念ながら、 objc_msgSend はObjective-Cランタイムの一部であり、オーバーライドできません。

グーグル検索で、Googleブックスに関する論文を見つけました。 -ALnSozvMceG_Abn39SCCA&sa = X&oi = book_result&ct = result&resnum = 1&ved = 0CAgQ6AEwAA#v = onepage&q =&f = false "rel =" noreferrer ">シャーロットピイルナウによるプロセス制御アプリケーションの反射アーキテクチャ。このペーパーでは、オブジェクトの isa クラスポインターをカスタムMetaObjectクラスのインスタンスにリダイレクトすることにより、ハッキングを紹介しています。したがって、変更されたオブジェクトを対象としたメッセージは、MetaObjectインスタンスに送信されます。 MetaObjectクラスには独自のメソッドがないため、変更されたオブジェクトにメッセージを転送することで、転送呼び出しに応答できます。

この論文には興味深いソースコードの一部は含まれていません。そのようなアプローチがCocoaに副作用をもたらすかどうかはわかりません。しかし、試してみるのは面白いかもしれません。

アプリケーションコードから送信されたメッセージを記録する場合、-forwardingTargetForSelector:ヒントはソリューションの一部です。
オブジェクトをラップする:

@interface Interceptor : NSObject
@property (nonatomic, retain) id interceptedTarget;
@end

@implementation Interceptor
@synthesize interceptedTarget=_interceptedTarget;

- (void)dealloc {
    [_interceptedTarget release];
    [super dealloc];
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"Intercepting %@", NSStringFromSelector(aSelector));
    return self.interceptedTarget;
} 

@end

次のようにします:

Interceptor *i = [[[Interceptor alloc] init] autorelease];
NSFetchedResultsController *controller = [self setupFetchedResultsController];
i.interceptedTarget = controller;
controller = (NSFetchedResultsController *)i;

そしてメッセージ送信のログがあります。インターセプトされたオブジェクト内から送信された送信は、元のオブジェクト「self」ポインターを使用して送信されるため、インターセプトされません。

外部から呼び出されたメッセージ(通常はデリゲートから呼び出され、どの種類のメッセージ、いつなどを表示する)のみをログに記録する場合、次のようにrespondsToSelectorをオーバーライドできます。

- (BOOL)respondsToSelector:(SEL)aSelector {
NSLog(@"respondsToSelector called for '%@'", NSStringFromSelector(aSelector));

// look up, if a method is implemented
if([[self class] instancesRespondToSelector:aSelector]) return YES;

return NO;

}

NSProxy および -forwardInvocation: および -methodSignatureForSelector: (または -forwardingTargetForセレクタ: 、メソッドを自分でいじるのではなく、単純に2番目のオブジェクトに向ける場合)

NSProxy は、 -forwardInvocation: onを実装するために設計されたクラスです。いくつかのメソッドがありますが、ほとんどの場合、それらを捕まえたくありません。たとえば、参照カウントメソッドをキャッチすると、ガベージコレクションの場合を除き、プロキシの割り当てが解除されなくなります。ただし、絶対に転送する必要がある特定のメソッドが NSProxy にある場合は、そのメソッドを具体的にオーバーライドして、 -forwardInvocation:を手動で呼び出すことができます。メソッドが NSProxy のドキュメントにリストされているからといって、 NSProxy がメソッドを実装することを意味するのではなく、すべてのプロキシされたオブジェクトがそれを持っていることが期待されることに注意してください。

これで問題が解決しない場合は、状況に関する詳細を追加してください。

おそらく NSObject -forwardInvocation メソッドが必要でしょう。これにより、メッセージをキャプチャし、再ターゲットしてから再送信できます。

メソッド呼び出しを独自のメソッド呼び出しでスウィズルできます。元の実装を呼び出します。スウィズルはclass_replaceMethod()で行われます。

メソッド呼び出し、いいえ。はい、メッセージを送信しますが、方法について適切な回答が必要な場合は、より詳細に説明する必要があります。

メソッドが呼び出されたときに何かをするために、イベントベースのアプローチを試すことができます。そのため、メソッドが呼び出されると、イベントがブロードキャストされ、イベントはリスナーによって取得されます。私は客観的なCには不向きですが、 NSNotificationCenter

ただし、「インターセプト」による場合「停止」を意味する場合、メソッドを呼び出す必要があるかどうかを判断するためのロジックが必要になる可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top