2008 04 27Dynamic method over* from a Javascript standpoint
MyObject.prototype.someFunction = newFunction will set a new class or instance method for all MyObject instances, MyObject.someFunction = newFunction sets a new method just for that instance. While the latter is not possible in ObjC, the former is thanks to the runtime functions, namely
-
class_addMethodto add a C function as a method to a class — we'll need to provide a signature that defines the function parameters and return values. For example, the signature ofdrawRect:isv24@0:4{_NSRect={_NSPoint=ff}{_NSSize=ff}}8(get it withmethod_getTypeEncoding) -
class_getInstanceMethodandclass_getClassMethodto get pointers (called implementations) to class and instance methods - once we have the implementations of our new and old methods, use
method_exchangeImplementationsto exchange them
To overload a class method, we add a new method to that class and exchange their implementations. Then when our new method is called, we do our job and call the original one. To add a method, we use either class_addMethod or a class category :
@implementation ExistingClass (MyOverrideMethod)
- (void)doStuff2
{
// do extra stuff
…
// call original method (this is not a recursive call as implementations have been swapped)
[self doStuff2]
}
@end
Be careful before overloading a method. If you overload NSButton's drawRect with a new method drawRect2:, and have a slider in your interface, you'll crash in [NSSlider drawRect:] — no such method drawRect2. Why ? NSButton does not have its own drawRect method : its drawing is done by its parent class, NSControl. method_exchangeImplementations will happily swap a parent class method (NSControl's drawRect) with a derived class method (NSButton's drawRect2), guaranteeing a crash in sibling classes (NSSlider, NSTextField). To overload NSButton's drawRect, no need to jump through hoops : adding a drawRect: method to NSButton with a category and calling [super drawRect:…] will work just fine ! :)
So before overloading a method, compare its implementation with the superclass implementation (get the superclass with class_getSuperclass, then compare the results of class_getInstanceMethod). If they differ, use the method_exchangeImplementations technique. If not, overload with a category method.
Objective-C 2.0 Runtime Reference
Dynamic overloading : sample code
Objective-C from Javascript
- KVC and KVO from a Javascript standpoint
- ObjC protocols from a Javascript standpoint
- Delegates from a Javascript standpoint
- Target+action from a Javascript standpoint
- Outlets from a Javascript standpoint
- Dynamic method over* from a Javascript standpoint
- The Responder Chain from a Javascript standpoint
- PerformSelector from a Javascript standpoint
- NIBs from a Javascript standpoint
- Events from a Javascript standpoint
Hi Karsten,
Ah yes, jrswizzle copies the parent implementation at the derived class level with class_addMethod. So it is simpler ! Thanks for the link.
wouldn't it be simpler to just use MethodSwizzling for that? Jonathan Rentzsch did a nice project to have a clean implementation of it. Michael Tsai bloged about it here: http://mjtsai.com/blog/2007/12/29/jrswizzle/
Karsten