Let's say ClassA
, ClassB
, and ClassC
are defined as follows:
@interface ClassA : NSObject {
}
- (void)methodA;
@end
@interface ClassB : ClassA {
}
- (void)methodB;
@end
@protocol ClassCProtocol <NSObject>
- (void)protocolMethodC;
@end
@interface ClassC : ClassA <ClassCProtocol> {
}
@end
To make things interesting, I also defined a @protocol
named ClassCProtocol
that inherits from the <NSObject>
protocol, as well as a ClassC
object that is a subclass of ClassA
and conforms to the <ClassCProtocol>
protocol (all that really means is that any object that conforms to the protocol is guaranteed to implement the -protocolMethodC
method).
The first thing to note is that in Objective-C, there isn't really a such thing as a derived class in the same sense as there is in C++: there's only single inheritance, so we generally talk about ClassB
being a subclass of ClassA
, or ClassC
being a subclass of ClassA
.
Then take the following code, assuming MDLoadObject()
is a function that will return an instance of ClassA
, ClassB
, or ClassC
based on whatever circumstances:
ClassA *MDLoadObject() {
ClassA *object = nil;
if (...) {
object = [[[ClassA alloc] init] autorelease];
} else if (...) {
object = [[[ClassB alloc] init] autorelease];
} else {
object = [[[ClassC alloc] init] autorelease];
}
return object;
}
@interface MDAppController : NSObject {
}
- (void)loadObject:(id)sender;
@end
@implementation MDAppController
- (void)loadObject:(id)sender {
ClassA *instanceOfClassABorC = MDLoadObject();
if ([instanceOfClassABorC isKindOfClass:[ClassB class]]) {
[(ClassB *)instanceOfClassABorC methodB];
} else if ([instanceOfClassABorC isKindOfClass:[ClassC class]]) {
[(ClassC *)instanceOfClassABorC protocolMethodC];
} else if ([instanceOfClassABorC respondsToSelector:@selector(protocolMethodC)) {
[(ClassC *)instanceOfClassABorC protocolMethodC];
} else {
}
}
@end
Since the highest common ancestor of classes ClassB
and ClassC
is ClassA
, we define the MDLoadObject()
function to return an instance of ClassA
. (Remember that in single inheritance all instances of ClassB
and ClassC
are also guaranteed to be instances of ClassA
).
The -loadObject:
method, then, shows the dynamism of Objective-C, and several ways you can inquiry about what type of object was returned from the MDLoadObject()
function at this point in time. Note that the -loadObject:
method could also be written without the casts and it would run just fine at runtime:
- (void)loadObject:(id)sender {
ClassA *instanceOfClassABorC = MDLoadObject();
if ([instanceOfClassABorC isKindOfClass:[ClassB class]]) {
[instanceOfClassABorC methodB];
} else if ([instanceOfClassABorC isKindOfClass:[ClassC class]]) {
[instanceOfClassABorC protocolMethodC];
} else if ([instanceOfClassABorC respondsToSelector:@selector(protocolMethodC)) {
[instanceOfClassABorC protocolMethodC];
} else {
}
}