非虚拟地调用Objective-C函数

非虚拟地调用Objective-C函数,objective-c,Objective C,是否可以强制Objective-C调用虚拟方法的特定实例,而不是通过标准的虚拟消息分派?我知道这通常不是一个好主意,但我想知道如何使用Objective-C运行时来实现 例如,给定实现-void foo的类A和B,其中B是A的子类,我想用B实例调用A上的foo方法,即使B通常会处理此消息 我知道我可以通过将A的foo方法的核心转移到一个新方法并委托给它来实现这一点,但是我想通过Objective-C运行时找到一些方法来实现这一点 注意:出于这个问题的目的,假设我不能更改A或B的源代码,并且我已经

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

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

我知道我可以通过将A的foo方法的核心转移到一个新方法并委托给它来实现这一点,但是我想通过Objective-C运行时找到一些方法来实现这一点

注意:出于这个问题的目的,假设我不能更改A或B的源代码,并且我已经仔细权衡了破坏封装的风险。

是理解运行时的一个很好的源代码;快速记忆辅助扫描显示标题为“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); 

马提亚斯说的。。。然而:

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

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

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

如果您不是B的实现者,那么这绝对不是一个坏主意。这几乎肯定会导致神秘的撞车者和/或不当行为。更糟糕的是,如果B实际上是一个系统框架的一部分,或者可以通过一个机制(而不是正在更新的应用程序)进行更新,那么你就有了一个定时炸弹,它可能会在任何时候在操作系统的任意配置上开始崩溃你的应用程序

具体而言:

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

直接调用实现将绕过任何正在使用的KVO。除非您碰巧抓取了一个派生方法实现,否则当该派生方法不再起作用时,您的行为将爆炸


为什么[super foo]不符合您的需要?您对所需内容的描述正是super关键字的作用。编辑:哦,除非,正如bbum所描述的,你想从B的实例之外调用-[A foo]。是的,我想一般地调用它-不一定是从B。我现在不能更改A或B的内容。OP听起来像是他们控制了A,因此可能是B,所以我有一种感觉[super foo]真的是最好/最简单的答案。这几乎就是我需要的。给定B的一个实例,我能让它以某种方式从A返回与选择器匹配的方法吗?或者我可以要求A提供一个与选择器匹配但没有实例的方法吗?instanceMethodForSelector可能就是我要查找的对象。[[target superclass]instanceMethodForSelector:]可以在NSObject文档中找到;你需要的是-methodForSelector:,而不是-methodForSelector:,因为[target superclass]返回一个类,而-methodForSelector:将不会响应该类。我理解这样做不好的原因,但为了更好地理解运行时,这更像是一个假设问题。是的;只是确保记录显示这是一个非常糟糕的主意