Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I remove instance methods at runtime in Objective-C 2.0?

Is it possible to remove methods added to a class with class_addMethod?

Or if I want to do this, must I keep creating classes at runtime with objc_allocateClassPair and adding different sets of methods to them to vary the methods implemented?

I'll accept answers that include hackery :-)

like image 960
Steve Weller Avatar asked Aug 22 '09 04:08

Steve Weller


2 Answers

You can't exactly "remove" a method, but you can get the same effect as a removal, by making the method just redirect everything to the message forwarding path (the code that will eventually call -forwardInvocation:). There are two ways to accomplish that:

  1. _objc_msgForward(), declared in /usr/include/objc/message.h but not included in the online documentation, can be used as the IMP for your method you are trying to remove. Because it's undocumented, it may be considered private or unsupported.
  2. You can call class_getMethodImplementation() with a selector that you know does not exist, and use the result as the IMP for the method you are trying to remove. Based on the documentation, this should have the same effect as the first option:

The function pointer returned may be a function internal to the runtime instead of an actual method implementation. For example, if instances of the class do not respond to the selector, the function pointer returned will be part of the runtime's message forwarding machinery.

In either case, it becomes as simple as:

method_setImplementation(methodToRemove, forwardingIMP);

Note that this will basically block out any superclass implementations, so you'll have to be more careful if any superclass might have a valid implementation that you want to keep. In such a case, you could get the IMP from the superclass or something similar.

like image 63
Justin Spahr-Summers Avatar answered Oct 17 '22 09:10

Justin Spahr-Summers


In short, you can't.

You could in the Objective-C 1.0 ABI/API via:

OBJC_EXPORT void class_removeMethods(Class, struct objc_method_list *) OBJC2_UNAVAILABLE;

But that function was removed in Objective-C 2.0 because removing methods is pretty much never the right answer. Certainly not often enough to justify the overhead incurred by supporting said feature.

Also removed from the ObjC2.0 ABI was the ability to directly access the class/method structures. They are now opaque so that they can be changed in the future without breaking binary compatibility.

What you could do, though, is use a custom proxy that varies the set of methods that it responds to. See documentation for the NSProxy class; http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html

Of course, this question begs the question "What are you trying to do?". Such on the fly meta-programming is atypical. Once a class is instantiated, it isn't normally considered desirable to change the set of methods it responds to under the assumption that previous instantiations may still depend on said methods.

like image 29
bbum Avatar answered Oct 17 '22 09:10

bbum