2011-09-22 85 views
0

是否可以强制Objective-C调用虚拟方法的特定实例,而不是通过标准虚拟消息调度?我知道这通常是一个糟糕的想法,但我想知道如何使用Objective-C运行时来完成它。例如,给定实现 - (void)foo的A和B类,其中B是A的子类,我想用B实例调用A上的foo方法(尽管B通常会处理这条信息)。非虚拟调用Objective-C函数

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

注意:就本问题而言,假定我无法更改A或B的来源,并且我仔细权衡了破坏封装的风险。

+1

为什么'[超级富]'不适合您的需求?你对你想要的内容的描述正是“super”关键字所做的。编辑:哦,除非像bbum描述,你要调用' - 从_outside_ B'的'一个实例[A FOO]'。 –

+0

是的,我想一般称之为 - 不一定是从B.我不能在这一点上改变A或B的内容。 – slipheed

+0

的OP使得它听起来就像他们对A(因此可能B)的控制,所以我有一种感觉'[超级富]'确实是最好/最简单的答案。 – matthias

回答

4

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

这里的地方,他会查询相应的函数指针运行时的例子,然后直接调用该函数:

//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); 
+0

这几乎是我所需要的。鉴于B的一个实例,可我已经还给我的方法从A选择以某种方式匹配?或者我可以问一个没有实例的匹配选择器的方法吗? – slipheed

+0

instanceMethodForSelector _might_是什么我要找的。 – slipheed

+1

'[[target superclass] instanceMethodForSelector:]'(可在NSObject文档中找到)可以做到这一点;你需要这个而不是'-methodForSelector:',因为'[target superclass']返回一个'Class','-methodForSelector:'不会响应。 – matthias

3

什么马蒂亚斯说...但是:

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

换句话说,你有foo第B要避免通过直接调用a的实现的实现?

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

如果你不是B的实现者,那么这是一个坏主意。它几乎保证会导致神秘不测和/或不正当行为。更糟糕的是,如果B实际上是系统框架的一部分,或者可能通过除更新的应用程序之外的机制进行更新,那么您有一个定时炸弹,可能会随时启动任何随机配置OS。

具体来说:

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

  • 直接调用实现将绕过任何KVO。除非你碰巧抓住一个派生的方法实现,那么当派生的方法不再起作用时,你的行为将会爆炸。

+0

我明白造成这种情况的原因很糟糕,但这更多的是为了更好地理解运行时间而提出的一个假设性问题。 Yup; – slipheed

+0

是的;只要确保记录显示这是一个非常糟糕的主意。 :) – bbum