Womble
Womble

Reputation: 5290

Objective-C subclass setup

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

Answers (3)

matt
matt

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

Andrey Chernukha
Andrey Chernukha

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

Chris Trahey
Chris Trahey

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

Related Questions