views:

106

answers:

3
+2  Q: 

Cocoa Grandfather

Is it possible to access the super class method of an objects super class (or grandfather)?

For instance:

GrandFatherObject : NSObject
SuperObject : GrandFatherObject
SelfObject : SuperObject

From SelfObject:

- (void)overriddenMethod
{
  // For Self
  someCode();

  // For Parent
  [super overriddenMethod];

  // For GrandParent
  ???
}

I only have access to SelfObject (Can't modify SuperObject or GrandFatherObject)

+5  A: 

Why would you want to do this? You should rethink your class design if you think this is necessary. You can always, of course, call super in the parent class's implementation of overriddenMethod.

For proper encapsulation, subclasses shouldn't need to know about anything other than their parent class. Otherwise you have tight, bi-directional coupling within the inheritance hierarchy. Nightmares.

Marc W
I agree that this is unlikely to ever be necessary, but it's not hard to imagine when you might want to do it. For example, if you're writing a class cluster, and the parent cluster class overrides `-init` to `[self release]` and return a new allocated object of the appropriate subtype, the subclasses would *not* want to call `[super init]` but might want to invoke `[grandsuper init]` instead
Dave DeLong
I did end up figuring out a way to do it without using the "grandsuper", but it was still complicated. My particular scenario: I put an NSView into an WebHTMLView (A little trick I'm working on to put cocoa views inside of WebView objects), and while they went in fine and looked great, I couldn't click on them. This is because WebHTMLView (a private class) redefines hitTest: so I subclassed WebView (my self), and overrode hitTest for WebView, checking if it was a hit that I wanted (and if it was) I would call grandparent (NSView) hitTest, otherwise Parent (WebHTMLView) hitTest. Works though
BadPirate
+8  A: 

Yes, you can do it, but it takes a bit more code than just invoking super.

More or less, it'd be something like this:

#import <objc/runtime.h>

struct objc_super grandsuper;
grandsuper.receiver = self;
grandsuper.class = class_getSuperclass(class_getSuperclass([self class]));

//if _cmd has a non-struct return value:
id grandsuperReturnValue = objc_msgSendSuper(&grandsuper, _cmd, arg1, arg2, ...);
Dave DeLong
Additionally, since all parameters send through objc_msgSendSuper use a var_arg list, all your method's parameters must be variable argument list compatible. e.g. float and short won't work (in a var_arg list they get promoted to double and int respectively and won't be parsed correctly by your method).
Matt Gallagher
+2  A: 

While playing with objc_msgSendSuper() is certainly fun, why don't you take the easy way and create a Category in the SelfObject implementation, something like

@interface SuperObject (ForSelfObject)
  - (id)grandFatherOverridenMethod;
@end

@implementation SuperObject (ForSelfObject)
  - (id)grandFatherOverridenMethod {
    return [super overridenMethod];
  }
@end

You said you can't modify SuperObject, that doesn't mean you can't extend it. Am I missing any major drawbacks here?

w.m
+1 clever solution! :)
Dave DeLong
virtual -1 (actually down voting would be harsh IMO) That would be a disaster because you are not extending the super object, you are changing part of its behaviour. It might be doing stuff in the method you bypass that is essential for its correct operation.
JeremyP