CommaToast
CommaToast

Reputation: 12238

In Objective C, how can I have subclasses inherit static class variables that, if set, won't change the variable's value for all children?

In Objective C, how can I have subclasses inherit static class variables that, if set, won't change the variable's value for all children?

Lets say I have abstract class Car. It has a static BOOL, "isSportsCar", that we set to zero.

Then in subclass SportsCar's init method, we set isSportsCar = YES.

My goal was so that all instances of SportsCar will return "YES" from the method, "isSportsCar" (which returns the static BOOL's value).

The problem is that all the other subclasses of Car, like LuxuryCar and Limousine, all now return YES from "isSportsCar".

I want to avoid having to declare the isSportsCar methods in all the subclasses.

But how can I make a class variable where each subclass will have its own instance of that variable?

Upvotes: 0

Views: 974

Answers (3)

CRD
CRD

Reputation: 53010

Your solution only fails to work because you used a static variable. If you had defined an instance variable, or a property, on the base class, then your scheme works.

Your base Car class does what it does now - sets the instance variable/property isSportsCar to NO in its init method. Any instance of Car, or any of its subclasses, now has a property isSportsCar which returns NO.

The init method of your subclass SportsCar first calls the init method of its superclass using [super init] - which sets isSportsCar to NO, then does its now initialising and sets isSportsCar to YES. Now for any instance of SportsCar, or any of its subclasses, isSportCar will return YES.

If you use a property for isSportsCar you can declare it as readonly in the public header file, and as readwrite in a private header file only subclasses import. That way subclasses can set the property but all others can only read it.

Using a property/instance variable is only required if the value might change. In the case of isSportsCar it is unlikely to change for a particular class. In that case you can just use an instance method, overriding as required in subclasses. So Car would contain:

- (BOOL) isSportsCar { return NO; }

and SportsCar would contain:

- (BOOL) isSportsCar { return YES; }

as with the property approach inheritance handles the rest and instances of Car, or any of its subclasses except SportsCar, return NO; while instances of SportsCar, and any of its subclasses, return YES.

HTH

Upvotes: 1

drekka
drekka

Reputation: 21883

You can't. At least not with static variables.

The idea of static variable are that they are values on the classes themselves, not the instances. So logically there will be one value across all instances, regardless of whether those instances are of the class where the variable was defined, or instances of subclasses. To have different values, you need to create instance variables or properties. Then the value can be different.

For example, you could define readonly properties and code a getter to return a hard coded value like this:

@interface Car:NSObject
@property (nonatomic, assign, readonly, getter=isSportsCar) BOOL sportsCar;
@end

@implementation Car 
-(BOOL) isSportsCar {
    return NO;
}
@end

@interface SportsCar:Car
@end

@implementation SportsCar 
-(BOOL) isSportsCar {
    return YES;
}
@end

However from the context of what you say, I suspect you want to known when you are dealing with a SportsCar in you code. Something like this:

if (car.isSportsCar) {...}

This is fine if you have various types of cards which can be sports cars, all running with the same class. But if you are creating different classes, you might want to save yourself the code and simply test the class itself:

if ([car isKindOfClass:[SportsCar class]]) {...}

Even if you then add a Bugatti class derived from a SportsCar class, this will still work. It all comes down to what you are trying to achieve.

My finally recommendation would be to remember the KISS principle and avoid creating variables or properties that effectively duplicate other data.

Upvotes: 1

rmaddy
rmaddy

Reputation: 318874

Don't do this using a static variable. Use a class method. So in the abstract base class Car you have:

Car.h:

+ (BOOL)isSportsCar;

Car.m:

+ (BOOL)isSportsCar {
    return NO;
}

Then in your SportsCar class you have:

SportsCar.m:

+ (BOOL)isSportsCar {
    return YES;
}

Then only classes inherited from SportsCar will return YES.

Upvotes: 2

Related Questions