非虚拟地调用Objective-C函数

时间:2011-09-22 19:45:50

标签: objective-c

是否可以强制Objective-C调用虚拟方法的特定实例,而不是通过标准的虚拟消息调度?我知道这通常是一个坏主意,但我想知道如何使用Objective-C运行时。

例如,给定实现 - (void)foo的类A和B,其中B是A的子类,我想用A实例调用A上的foo方法(即使B通常会处理这个消息)。

我知道我可以通过将A的foo方法的内容移动到新方法并委托给它来实现这一点,但我想通过Objective-C运行时找出一些方法来实现这一点。

注意:出于这个问题的目的,假设我不能改变A或B的来源,并且我仔细权衡了打破封装的风险。

2 个答案:

答案 0 :(得分:4)

This page是理解运行时的重要来源;一个快速的记忆辅助扫描显示标题为“那么objc_msgSend中发生了什么?”部分?是一个立即回答的好地方,但整篇文章将真正帮助您了解发生的事情。

这是一个示例,他在运行时查询相应的函数指针,然后直接调用函数:

//declare C function pointer
int (computeNum *)(id,SEL,int);

//methodForSelector is COCOA & not ObjC Runtime
//gets the same function pointer objc_msgSend gets
computeNum = (int (*)(id,SEL,int))[target methodForSelector:@selector(doComputeWithNum:)];

//execute the C function pointer returned by the runtime
computeNum(obj,@selector(doComputeWithNum:),aNum); 

答案 1 :(得分:3)

Matthias说的是......但是:

  

例如,给定A类和B类实现 - (void)foo,其中B   是A的子类,我想用A调用A上的foo方法   实例(即使B通常会处理此消息)。

换句话说,您希望通过直接调用foo的实现来避免B上的a实现?

显然,如果你是B的实施者,那么这是微不足道的;只需实施适当的逻辑来确定何时需要它并调用[super foo];

如果你不是B的实施者,那么这不是一个坏主意。它几乎可以保证导致神秘的骚扰和/或不当行为。更糟糕的是,如果B实际上是系统框架的一部分或可能通过您的应用程序更新之外的其他机制更新的东西,那么您有一个滴答作响的定时炸弹可能会随时在任何随机配置上崩溃您的应用程序OS。

具体做法是:

  • B foo可能不是自包含的;它可能会在调用A foo之前/之后执行操作,这些内部状态可能会在以后继续正确操作时需要。你正在用大锤打破封装。

  • 直接调用实现将绕过任何KVO。除非您碰巧抓住派生方法实现,否则当派生方法不再有效时,您的行为将会爆炸。