EDIT: Problem solved! After cleaning and rebooting it just disappeared! I don’t know what caused this!
This has caused me headaches for a full day now:
In Xcode 3.2 everything worked excellent. Then I switched to 4.2 and suddenly a class inheritance does not work anymore.
I have a class TheSuperclass and TheSubclass : TheSuperclass. To simplify testing, I really created them like this. There’s no more code than what you can see here:
// TheSuperclass.h
@interface TheSuperclass : NSObject {
}
// subclasses must override this method
- (id)returnSomethingUseful;
@end
// TheSuperclass.m
#import "TheSuperclass.h"
@implementation TheSuperclass
- (id)returnSomethingUseful {
NSLog(@"Dude, you have to override -returnSomethingUseful");
return nil; // subclasses override this method!
}
- (id)init {
if ((self = [super init])) {
obj = [self returnSomethingUseful]; // TEST
NSLog(@"TheSuperclass initialized: %@", obj);
}
return self;
}
@end
// TheSubclass.h
#import "TheSuperclass.h"
@interface TheSubclass : TheSuperclass {
}
@end
// TheSubclass.h
#import "TheSubclass.h"
- (id)returnSomethingUseful {
NSLog(@"Correct method called!");
return usefulObject;
}
TheSubclass *foo = [[TheSubclass alloc] init]; // remember: init of superclass calls the method
// Getting the NSLog: "Dude, you have to override -returnSomethingUseful"
id bar = [foo returnSomethingUseful]; // now call it directly on foo
// Getting the NSLog: "Correct method called!"
TheSuperclass declares a template method, that is, a method which just does nothing, returns nil and is intended for subclassing:
- (id)returnSomethingUseful {
NSLog(@"Dude, you have to override -returnSomethingUseful");
return nil; // subclasses override this method!
}
In TheSubclass, I simply override that template method. And of course I COPIED the implementation out of TheSuperclass to get it 100% right. No typo. That’s a checked fact. Looks like this:
- (id)returnSomethingUseful {
NSLog(@"Correct method called!");
return usefulObject;
}
In the implementation of TheSuperclass a piece of code calls [self returnSomethingUseful] in order to get that object from the template method. It’s a great pattern and I have used it a lot. It always worked exactly like this.
But now it appears that even though I create an instance of TheSubclass, it always calls the WRONG method. The one from TheSuperclass, instead of the one it should (which is the overwriding method of course)
I’ve checked that at least 100 times! Seriously, it is an instance of TheSubclass. It calls the init method of TheSuperclass giving me NSLogs.
Now the really strange part: When I call that method on my TheSubclass object “from outside”, it works:
TheSubclass *foo = [[TheSubclass alloc] init];
id bar = [foo returnSomethingUseful];
// Getting the NSLog: "Correct method called!"
So to emphasize it: When I call [self returnSomethingUseful] from within the implementation of TheSuperclass, it calls the WRONG implementation (which is the one of the superclass, rather than the overwritten one in the subclass.
So how can I work around this? Where does this possibly come from? Is this a problem in the runtime, maybe caused by an error in the compiler?
LLVM clearly is able to implement simple subclassing correctly. Thousands of programs use it every day, so this is not a problem to be worked around if you are writing standard code (not trying anything tricky or undocumented). Here are the things you should do:
[self class]to make sure you really are what you think you are.isapointer (easy to find; search for->isain your code).init. This is the most likely place to have done something over-tricky. Make sure you’re following the simple patterns.