Image:CocoaNav icon.png

PARMANOIR

Dynamic method over* from a Javascript standpoint

In Javascript, you can easily override or overload any method of any object : 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 of drawRect: is v24@0:4{_NSRect={_NSPoint=ff}{_NSSize=ff}}8 (get it with method_getTypeEncoding)
  • class_getInstanceMethod and class_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

Karsten
2008 04 28

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

Patrick Geiller
2008 04 28

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.

2008 07 25Where in build phases is that file ?
2008 07 192Imagine clickable error messages
2008 07 18Succulent Stormhoek
2008 07 173Loving the for
2008 07 12(Parmanoir) Feed now validates
2008 07 108Telling classes from instances
2008 07 08Comma Trick
2008 07 06Using libffi
2008 07 04BridgeSupport's type and type64
2008 07 042Clickable Disabled MenuItems
2008 07 026Less bugs through compiler optimizations
2008 06 251CocoaNav JS, a light CocoaNav for Safari
2008 06 232NSWindow goodies : bottomCornerRounded, usesLightBottomGradient
2008 06 222Inspecting NSUndoManager's undo stack
2008 06 16Cocoa Regular Expressions via JavascriptCore
2008 06 15Crossing the WebKit bridge
2008 06 08Double and Triple Click
2008 06 05Photoshop-like compositing with Core Animation
2008 06 052One way binding to NSSlider
2008 05 30Threaded Core Animation, Part Deux
Image:rss.png
Image:rss.png

Powered by MediaWiki

Hi ! I'm learning Cocoa to (hopefully !) become an indie developer.

I've written software all my professional life, in C++, PHP, Javascript. I've designed websites and web interfaces. My last venture went into flames as clients were happy but didn't like paying very much.

I've had little luck in the B2B world, I'm hoping for a better future writing Mac applications.

Planet Cocoa