2008 12 10Whoops ! super is not runtime
super
is resolved at compile time. This becomes a problem if you use a class to store methods that you add at runtime to other classes : [super someMethod]
will then fail or work by coincidence.
In JSCocoa, each ObjC class written in Javascript can hold arbitrary Javascript data. An NSButton
-based class can hold random data without having to declare instance variables, storing variables within a Javascript hash held by the class. To clean that hash, JSCocoa overloads dealloc
by calling class_addMethod
with the address of deallocAndCleanupJS
, the JSCocoa cleanup method.
deallocAndCleanupJS
is stored in an NSObject
-based class. And super
is resolved at compile time. You can see where this goes : in an NSButton
-based class, [super dealloc]
calls dealloc
from NSObject
rather than from NSButton
. Which is bad.
// Source class for helper methods, derived from NSObject @implementation JSCocoaMethodHolder - (void)deallocAndCleanupJS { // Do Javascript cleanup here ... // Call parent dealloc -> Here this will ALWAYS call NSObject's dealloc [super dealloc] } @end |
// Define a new NSObject-based Class in JSCocoa defineClass('ApplicationController < NSObject', ...) // NSObject → ApplicationController // ApplicationController's dealloc will call NSObject dealloc — that's what we want but it's a coincidence ! :) |
// Define a new NSButton-based Class in JSCocoa defineClass('MyButton < NSButton', ...) // NSObject → NSButton → MyButton // MyButton's dealloc will call NSObject dealloc instead of NSButton dealloc — that's a bug ! |
To call the correct method, we need to switch from a compile time super
call to a runtime super
call :
// Compile time super call - INCORRECT [super dealloc]; // Runtime super call - CORRECT ! struct objc_super s = { self, [self superclass] }; objc_msgSendSuper(&s, @selector(dealloc));
MyButton
will then correctly call the the NSButton
dealloc method. As super
is not runtime, use objc_msgSendSuper
for a runtime super
call.