views:

127

answers:

1

I found this related question: http://stackoverflow.com/questions/279158/how-do-i-use-composition-with-inheritance

I would like to do the same with Objective-C, that is to say that a GenericView knows that its property obj is a GenericObject, and that a SpecializedView knows that the very same obj property is a SpecializedObject.

Here is an example that will be clearer:

//
//  Example.m

#import <UIKit/UIKit.h>

/* HEADER */

// Electrical Machine
@interface ElectricalMachine : NSObject {
}
- (void)plugIn;

@end

// Toaster
@interface Toaster : ElectricalMachine {
}
- (float)getThermostat;

@end

// GenericView
@interface GenericView : NSObject {
    ElectricalMachine *machine;
}
- (void)doSomethingGeneric;
@property (nonatomic, retain) ElectricalMachine *machine;

@end

//SpecializedView
@interface SpecializedView : GenericView {
}
- (void)doSomethingSpecialized;
@end


/* IMPLEMENTATION */

// GenericView
@implementation GenericView

@synthesize machine;

- (void)doSomethingGeneric {
    Toaster *toaster = [[Toaster alloc] init];
    [toaster plugIn];
    self.machine = toaster;
    [toaster release];
}

@end

// SpecializedView
@implementation SpecializedView

- (void)doSomethingSpecialized {
    /* ERROR HERE
     * Incompatible types in initialization
     * 'ElectricalMachine' may not respond to '-getThermostat'
     */
    float r = [machine getThermostat];
    r = r;
    // ...
}

@end

As you see, I get an error at the end, because for SpecializedView the machine property is an ElectricalMachine, not a Toaster.

Thank you very much for your help!

Old Question

Here is the first version of my question, which was maybe too cryptic:

I have the following generic view:

@interface GenericView {
    GenericObject obj;
}

- (id)doSomething;

I also have the following specialized view:

@interface SpecializedView : GenericView {
}

- (id)doSomethingElse;

I have the following object:

@interface GenericObject {
}

- (id)plugIn;

and the following specialized object:

@interface SpecializedObject : GenericObject {
}

- (float)toastTime;

Let's say I want GenericView to handle GenericObject, and SpecializedView to handle the same object, knowing that it is SpecializedObject.

Let me explain by showing implementations:

GenericView doSomething

- (id)doSomething {
    [obj plugIn];
}

SpecializedView doSomethingElse

- (id)doSomethingElse {
    // ERROR here
    float time = [obj toastTime];
}

I will get the following warning: 'GenericObject' may not respond to '-toastBread' and the following error: Incompatible types in assignement

Which is logical, since I have defined the type of obj as GenericObject. I want to be able to use methods from GenericObject in GenericView, and methods from SpecializedObject in SpecializedView. Is there a way to precise that obj has to be a GenericObject in GenericView to be handled, and has to be a SpecializedObject to be dealt with in SpecializedView, without adding a property? How would you do that?

A: 

Objective-C is a dynamically-typed language and methods are resolved at runtime, not compile time. If in SpecializedView, obj is in fact of an object of type SpecializedObject (even though it's declared as GenericObject), it will in fact respond to a toastBread message. The compiler will generate a warning but you can ignore it.

If SpecializedView may have both GenericObjects and SpecializedObjects, you can make sure that obj responds to toastBread using the respondsToSelector: message (inherited from NSObject):

if ([obj respondsToSelector:@selector(toastBread)]) {
    [obj toastBread];
}
mipadi
Thank you for your answer, I tried your solution but for a reason I don't understand, it does not work. Let's say that I am trying to get a value from [obj toastTime], and it won't work. Compilation says: "incompatible types in assignment". I tried to add an abstract method in GenericObject, but it won't work.
charlax
In your example, `toastTime` returns an object of type `id`, but you're assigning it to a `float`. An `id` is not a `float` (it's actually a pointer) and thus cannot be assigned to a variable of type `float`.
mipadi
Sorry, my example was wrong, even by defining the type that toastTime returns as a ‘float‘, it won't work.
charlax
To remove the warning you have to cast the object to the type you know it to be. [(Toaster *)obj toastTime];
monowerker
Thank you very much monowerker, your solution is perfect!
charlax