30

I want to call a method of super class of a super class, without breaking the inheritance chain. Something like this:

+(id) alloc 
{
    return [super.super alloc];
}

Is there a way to achieve this ?

Do not confuse with behavior offering by superclass method, discussed here.


UPD:

A few words about super and superclass differences.

Lets say, we have AClass and SuperAClass. As follows from their names AClass inherits SuperAClass. Each of them has an implementation of a method -(void) foo;

AClass implements one of the following class methods:

1. superclass:

+(id) alloc {
    return [[self superclass] alloc];
}

2. super:

+(id) alloc {
    return [super alloc];
}

Now, suppose these 2 lines of code:

AClass *AClassInstance = [AClass alloc];
[AClassInstance foo];

In first case (using superclass), SuperAClass's foo method will be called. For the second case (using super), AClass's foo method will be called.

Community
  • 1
  • 1
Martin Babacaev
  • 6,240
  • 2
  • 19
  • 34
  • #1: I believe you’ve mixed the title of your examples (1. super, 2. superclass) with the actual code. –  Feb 24 '11 at 11:19
  • #2: `AClass AClassInstance = [AClass alloc];` is not valid since Objective-C objects must live on the heap and hence require pointers in their declarations. –  Feb 24 '11 at 11:20
  • #3: You cannot send `[AClassInstance foo]` since `AClassInstance` is not a class and `+foo` is a class method. –  Feb 24 '11 at 11:20
  • #4: `alloc` is a class method, hence `+ (id)alloc` –  Feb 24 '11 at 11:24
  • If might help if you describe textually what behaviour you’re expecting. –  Feb 24 '11 at 11:25
  • Thanks for #1 #2 #3 #4 remarks, fixed. The behavior is simple, I would like to access `foo` of AClass instead of their SuperAClass (or questionable SuperSuperAClass). – Martin Babacaev Feb 24 '11 at 12:19
  • 1
    You should move `solution` into an answer (out of the question area.) (a) it's difficult to find/read and (b) allows people to vote on the solution. Also more *The StackOverflow Way* :) – Olie Oct 01 '14 at 20:34
  • @Olie done. BTW, when this question has been asked, answering to your own questions was not really in _StackOverflow Way_ ;) – Martin Babacaev Oct 01 '14 at 21:55

2 Answers2

37

In your particular example, +superclass is actually the way to go:

+ (id)someClassMethod {
    return [[[self superclass] superclass] someClassMethod];
}

since it is a class method, hence self refers to the class object where +someClassMethod is being defined.

On the other hand, things get a tad more complicated in instance methods. One solution is to get a pointer to the method implementation in the supersuper (grandparent) class. For instance:

- (id)someInstanceMethod {
    Class granny = [[self superclass] superclass];
    IMP grannyImp = class_getMethodImplementation(granny, _cmd);
    return grannyImp(self, _cmd);
}

Similarly to the class method example, +superclass is sent twice to obtain the supersuperclass. IMP is a pointer to a method, and we obtain an IMP to the method whose name is the same as the current one (-someInstaceMethod) but pointing to the implementation in the supersuperclass, and then call it. Note that you’d need to tweak this in case there are method arguments and return values different from id.

3

Thanks to Bavarious who inspired me to involve some runtime staff.

Briefly, the desired hypothetical line:

return [super.super alloc];

can be transformed in this "real" one:

return method_getImplementation(class_getClassMethod([[self superclass] superclass], _cmd))([self class], _cmd);

To make it relatively more clear, it can be expanded as follow:

Method grannyMethod = class_getClassMethod([[self superclass] superclass], _cmd);
IMP grannyImp = method_getImplementation(grannyMethod);
return grannyImp([self class], _cmd);
Community
  • 1
  • 1
Martin Babacaev
  • 6,240
  • 2
  • 19
  • 34