Reputation: 5290
I have 3 Objective-C classes:
Animal - a subclass of NSObject
Feline - a subclass of Animal
Cat - subclass of Feline
Each of these three classes implement (what I thought was) its own private method (-private_Setup), for setup:
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self private_Setup];
}
return self;
}
Same thing in the Feline and Cat classes.
A list of required classes is provided at runtime, so I am creating instances of the various classes, depending on a list of class names.
e.g.
NSString *className = ... // @"Animal", @"Feline" or @"Cat".
id animal = [[NSClassFromString(className) alloc] init];
Problem:
If I create an instance of Cat, -private_Setup is being called multiple times, for each step in the inheritance chain. For example, the calling chain for a Cat:
-[Cat init]
-[Feline init]
-[Animal init]
-[Cat private_Setup] // First!
then, from:
-[Feline init]
-[Cat private_Setup] // Second!
then, from:
-[Cat init]
-[Cat private_Setup] // Third!
Thus, what I thought was a method private to each class, is being called after each -init in the hierarchy.
Could someone please advise how I could either fix this issue or redesign my setup strategies? Thankyou.
[edited, appended for clarity]
Some form of setup is required at each level of the inheritance, to supply data particular to that level. e.g. Cat specific settings.
Thus, what I need is for a Cat object to be fully set up as an Animal, as a Feline, and as a Cat.
I guess one approach is to have different setup method names at each level. e.g. setupAnimal, setupFeline, setupCat.
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupAnimal];
}
return self;
}
// in Feline:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupFeline];
}
return self;
}
// in Cat:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupCat];
}
return self;
}
Is there a better, more preferred design than this?
Upvotes: 2
Views: 79
Reputation: 534885
You are saying super init
and super's init
calls private_Setup
, so why are you surprised?
I guess you're surprised because you expect each init
in the chain to call its own class's private_Setup
. But the thing to understand is that meaning of self
changes depending on the original class of the instance that started the chain (polymorphism).
So, for example, if you call self private_Setup
from Animal's init
during the process of initializing a Cat, it is Cat's private_Setup
that will be called. Thus, with the arrangement you've made, it is exactly true that on initialization of a Cat, Cat's private_Setup
will be called three times and none of the others will be called.
The solution is simple: don't use an extra method. It is a capital mistake to have an initializer call any methods (and the problem you're having is one of the reasons why it's a mistake). Instead, simply perform the setup in init
itself. That is what it's for.
Upvotes: 1
Reputation: 21808
I think you should call private_Setup
method just once - in Animal
's init
. That's all. Implement in all subclasses, call just once in supercalass
You're saying that you need a different form of setup for each subclass. Of course! That's why what you do is you implement private_Setup
in every subclass. Implement just like you need it for every particular subclass. It's called overriding. Inside overridden method call [super private_Setup]
. You'll get exactly what you need.
Upvotes: 1
Reputation: 18290
If I understand correctly, you are implying that the call to private_Setup happens in all of your subclasses' init methods too.
Remove the call to private_Setup from all but the top (e.g. Animal) init method. As long as all of them call [super init]
, you'll get exactly one call to private_Setup.
Upvotes: 0