我可以拦截在Objective-C的方法调用? 怎么样?
编辑:“ 马克·鲍威尔的回答给了我一个局部的解决方案,-forwardInvocation方法。 但文档指出,当一个物体被发送对于其没有对应的方法的消息-forwardInvocation才调用。 我想在任何情况下被调用的方法,即使接收器确实有一个选择。
我可以拦截在Objective-C的方法调用? 怎么样?
编辑:“ 马克·鲍威尔的回答给了我一个局部的解决方案,-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@:");
你可以得到目标C运行时更详细的文档 。
拦截方法在Objective-C调用(asuming这是一个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运行的一部分,不能被重写。
谷歌搜索,我发现在谷歌图书的论文: 由夏洛特PII Lunau过程控制应用的反射架构 。 本文通过重定向对象的介绍黑客攻击isa
类指针到自定义元对象类的一个实例。 因而旨在被修改的对象的消息发送到元对象实例。 由于元对象类有没有自己的方法,它可以通过随后将消息转发到已修改的对象应对前进调用。
本文不包括源代码的有趣的位,我不知道,如果这种做法将在可可的副作用。 但是,它可能是有趣的尝试。
如果你想记录的消息从应用程序代码发送的-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;
和消息发送,你将有一个日志。 注意,并将从监听对象内发送不会被拦截,因为他们将使用原始对象的“自我”指针被发送。
如果你只是想记录从外部调用的消息(通常代表呼吁,看看哪一种的消息的时候,等),可以覆盖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:
或-forwardingTargetForSelector:
如果你只是指挥它到第二个对象,而不是用自己的方法摆弄)。
NSProxy
是专为执行一类-forwardInvocation:
对。 它有几个方法,但主要是你不希望他们被抓获。 例如,醒目的引用计数方法将防止代理被释放,除了垃圾收集下。 但是,如果有具体的方法NSProxy
,你绝对需要转发,可以专门重写方法,并调用-forwardInvocation:
手动。 这样做仅仅是因为一个方法在下面列出音符NSProxy
文档并不意味着NSProxy
实现它,仅仅是预计所有代理的对象都有它。
如果这不会为你工作,提供有关情况的其他详细信息。
也许你想NSObject
的-forwardInvocation
方法。 这可以让你捕捉到一条消息,重新定位它,然后重新发送。
你可以用你自己的,它不不管你想在“拦截”做,并呼吁通过对原执行的一个调酒方法调用。 混写与class_replaceMethod()完成。
一个方法调用,没有。 消息发送,是的,但你将不得不多很多描述性的,如果你想有一个很好的答案如何。
做一些事情,当一个方法被调用时,你可以尝试的活动为基础的方法。 因此,当方法被调用时,它广播的事件,这是任何听众回升。 我不是伟大的目标C,但我只是想出了类似的东西使用NSNotificationCenter可可。
但是,如果通过“拦截”你的意思是“停止”,那么也许你需要更多的逻辑来决定将来的方法应该是在所有调用。