我可以拦截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中的拦截方法调用(假设它是一个Objective-C,而不是C调用)是通过一种名为 方法调配的技术完成的。

您可以在此处找到有关如何实施 的简介。有关如何在实际项目中实现方法调配的示例,请查看 OCMock ( Objective-C的隔离框架。

在Objective-C中发送消息被转换为函数 objc_msgSend(receiver,selector,arguments)或其变体之一 objc_msgSendSuper 的调用objc_msgSend_stret objc_msgSendSuper_stret

如果可以更改这些功能的实现,我们可以拦截任何消息。不幸的是, objc_msgSend 是Objective-C运行时的一部分,无法覆盖。

通过Google搜索我在Google图书上发现了一篇论文: Charlotte Pii Lunau的过程控制应用反射架构。本文通过将对象的 isa 类指针重定向到自定义MetaObject类的实例来引入hack。因此,用于修改对象的消息将发送到MetaObject实例。由于MetaObject类没有自己的方法,因此它可以通过将消息转发给修改后的对象来响应转发调用。

本文不包括源代码的有趣内容,我不知道这种方法是否会在Cocoa中产生副作用。但尝试可能会很有趣。

如果要从应用程序代码中记录消息发送,-forwardingTargetForSelector:tip是解决方案的一部分。
包裹你的物体:

@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选择器: ,如果您只是将其指向第二个对象而不是自己摆弄该方法。)

NSProxy 是一个用于实现 -forwardInvocation:的类。它有一些方法,但大多数情况下你不希望它们被捕获。例如,捕获引用计数方法将阻止代理被释放,除非在垃圾回收下。但是如果您绝对需要转发 NSProxy 上的特定方法,则可以专门覆盖该方法并手动调用 -forwardInvocation:。请注意,仅仅因为 NSProxy 文档中列出的方法并不意味着 NSProxy 实现它,只是期望所有代理对象都拥有它。

如果这对您不起作用,请提供有关您情况的其他详细信息。

也许你想要 NSObject -forwardInvocation 方法。这允许您捕获消息,重新定位它然后重新发送它。

您可以使用自己的方法调用方法调用,这可以执行您想要执行的操作“拦截”操作。并调用原始实现。 Swizzling是通过class_replaceMethod()完成的。

方法调用,没有。发送一条消息,是的,但是如果你想要一个很好的答案,那么你将需要更具描述性。

要在调用方法时执行某些操作,您可以尝试基于事件的方法。因此,当调用该方法时,它会广播一个由任何侦听器拾取的事件。我对目标C不太满意,但我只是用 NSNotificationCenter

但如果通过“拦截”你的意思是“停止”,那么你可能需要更多的逻辑来决定应该调用该方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top