非虚拟调用 Objective-C 函数

发布于 2024-12-06 02:02:35 字数 331 浏览 0 评论 0原文

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

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

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

注意:出于本问题的目的,假设我无法更改 A 或 B 的来源,并且我已经仔细权衡了破坏封装的风险。

Is it possible to force Objective-C to call a specific instance of a virtual method, rather than going through the standard virtual message dispatch? I know this is generally a Bad Idea, but I'd like to know how to do it using the Objective-C runtime.

For example, given class A and B that implement -(void) foo, where B is a subclass of A, I'd like to call the foo method on A with the B instance (even though B would normally handle this message).

I know that I can make this happen by moving the guts of A's foo method to a new method and delegating to it, but I'd like to figure out some way to do this through the Objective-C runtime.

NOTE: For the purposes of this question, assume that I can't change the source of A or B and I've carefully weighed the risks of breaking encapsulation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

灯角 2024-12-13 02:02:36

此页面是了解运行时的重要来源;快速内存辅助扫描显示标题为“那么 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); 

This page is a great source for understanding the runtime; a quick memory-assisted scan shows that the section titled "So what happens in objc_msgSend anyway?" is a good place to start for an immediate answer, but the article as a whole will really help you understand what goes on.

Here's an example where he queries the runtime for the appropriate function pointer, then calls the function directly:

//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); 
蓝咒 2024-12-13 02:02:36

马蒂亚斯所说的……然而:

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

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

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

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

具体来说:

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

  • 直接调用实现将绕过任何正在运行的 KVO。除非您碰巧获取了派生方法实现,否则,当该派生方法不应再发挥作用时,您的行为将会爆炸。

What Matthias said... however:

For example, given class A and B that implement -(void) foo, where B
is a subclass of A, I'd like to call the foo method on A with the B
instance (even though B would normally handle this message).

In other words, you have an implementation of foo on B that you want to avoid by calling a's implementation directly?

Obviously, if you are the implementer of B, then this is trivial; just implement the appropriate logic to determine when it is needed and call [super foo];.

If you are not the implementer of B, then this is beyond a bad idea. It is pretty much guaranteed to lead to mystery crashers and/or misbehavior. Worse, if B is actually a part of a system framework or something that may be updated via a mechanism other than your app being updated, then you have a ticking time bomb that may start crashing your app at any time on any random configuration of the OS.

Specifically:

  • B's foo may not be self contained; it may do stuff before/after calling A's foo that sets up internal state that may later be required for continued correct operation. You are breaking encapsulation with a sledgehammer.

  • calling the implementation directly is going to bypass any KVO in play. Unless you happen to grab a derived method implementation, at which point, your behavior is going to explode when that derived method should no longer be in play.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文