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_addMethod
to 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_getInstanceMethod
andclass_getClassMethod
to get pointers (called implementations) to class and instance methods - once we have the implementations of our new and old methods, use
method_exchangeImplementations
to 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