slipheed
slipheed

Reputation: 7278

Call an Objective-C function non-virtually

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.

Upvotes: 0

Views: 118

Answers (2)

bbum
bbum

Reputation: 162722

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.

Upvotes: 3

matthias
matthias

Reputation: 2499

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); 

Upvotes: 4

Related Questions