views:

79

answers:

4

Hi, i need to call a grandparent method of my class.

@class Grandparent
+--->@class Parent   
     +---->@class Child

Every class implement a method:

-(void)foo

If i want to call the parent method foo from child class i use:

[super foo]

If i want to call grandparent's foo, how can i do? It's not possible to call

[super [super foo]]

Ant ideas?

A: 

if you really wanted to do this (not totally sure why), you would rig the Parent to call the GrandParent ([super foo]). Then when the Child Foo calls the Parent Foo, it would call the GrandParent Foo.

optionally, you could just create a method on the parent that called [super foo].

Tony Abrams
+5  A: 

You can, of course, accomplish this with the help of the parent class. If your foo calls [super foo] and your superclass then in turn calls [super foo] because it expects this behavior, then you're all set. This is a common pattern (e.g. -init and -dealloc).

But you can't jump directly using normal Obj-C syntax. Every subclass defines its own set of semantics for a class around its state and methods. If you could arbitrarily call implementations anywhere up your inheritance chain without the intermediate implementations knowing anything about it, then no implementation would have any guarantees about the integrity of its own state, and it would break the abstractions around classes.

In other words, and I hate being the guy that says this, you should rethink your design if this seems to be what you really want to do. (If so, feel free to open a new question to discuss the design of your object model. People here will be happy to assist.)

That said, technically, I suspect you can accomplish this by dealing directly with the Obj-C runtime. You can get your object's class reference, then its superclass, then its superclass, and get the method implementation you want from it. Then call it with your object. Code for this is an exercise for the reader. :) Here are the docs.

quixoto
I'm a c++ programmer and if i want i can callvoid Child::foo(){ Grandparent::foo();}It's a normal way to proceed...
Chiodo
Chido, this is the main difference in Obj-C is that method calls are determined at run-time. When you call [foo bar] you're not calling foo::bar(), you're asking "if you have bar(), execute it" which is an entirely different thing. You can add and remove methods at run time - check out Aspect Programming http://davedelong.com/blog/2009/04/13/aspect-oriented-programming-objective-c
Stephen Furlani
@Chiodo: Yup, you can. But that ability to explicitly specify a base class on which to invoke `foo` is really a side-effect of multiple inheritance; since there can be more than one base class, you need to be able to say whose `foo` you're talking about. That you can also specify `Grandparent` there seems incredibly fragile to me for multiple reasons, and something to be avoided. My opinions about design aside though, you just can't do the same in Obj-C. The normal pattern here is to call through the immediate parent class.
quixoto
A: 

When you're on the iPhone, you'll see a design pattern like this:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

if you create a new sub-class of UIViewController. As others have suggested, you should follow this pattern when overloading methods in sub-classes.

@implementation Grandparent
    - (void) printSelf
    {
        NSLog(@"Grandparent");
    }
 @end 

@implementation Parent
    - (void) printSelf
    {
        [super printSelf];
        NSLog(@"Parent");
    }
@end 

@implementation Child
    - (void) printSelf
    {
        [super printSelf];
        NSLog(@"Child");
    }
@end 

I don't think you can do the following, because method calls are determined at run-time, not compile-time. This would probably work for Java or C++ though, because of the binding and dispatch rules of the languages.

@implementation Child
    - (void) printSelf
    {
        [(Granparent *)self printSelf]
    }
@end

Try it, but I doubt it will work.

Stephen Furlani
It won't work because the cast doesn't make a difference. If `self` is *actually* a member of class `Child`, it will still get the `printSelf` message and-- as you suspect--dispatch it the same way, which is to say directed at the most-derived implementation.
quixoto
Also, all methods in Java and virtual methods in C++ are dispatched on the run time type of the receiver not the static type. It also doesn't really have much to do with strong-typed versus weak-typed but about the binding and dispatch rules of the language.
Geoff Reedy
@quixoto I didn't think it would. @Geoff, I'll change my language... terminology never appropriately sticks in my mind.
Stephen Furlani
+1  A: 

If you feel like you need to do this, it's probably a bad design. You should rethink what you're doing along the lines of quixoto's answer. quixoto mentioned the objective c runtime library, but NSObject has instance and class side methods to do that stuff. Like quixoto, I'll leave this as an exercise for you. The methods to look at are -(Class)class, +(Class)superclass, +(IMP)instanceMethodForSelector:SEL and you'll need to read the section about the SEL and IMP types and how to call methods through IMPs.

If you write the code and it looks awful (it will, don't worry), it's probably because you're not supposed to do it.

Geoff Reedy
How many teachers there are! I've changed the design... 2 minutes modify and no home work.
Chiodo