Reputation: 7278
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
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
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