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?
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
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
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
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