Reputation: 641
In the second chapter of his iOS Programming book, Joe Conway describes using 'self' in class methods in the event of subclassing. I understand this concept and have a question about the issue of subclassing.
Background: We created a Possession class whose class method +randomPossession looks like this:
+(id)randomPossession
{
NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shiny", nil];
NSArray *randomNounList = [NSArray arrayWithObjects:@"Bear", @"Spork", @"Mac", nil];
unsigned long adjectiveIndex = rand() % [randomAdjectiveList count];
unsigned long nounIndex = rand() % [randomNounList count];
NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]];
int randomValue = rand() % 100;
NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c",
'0' + rand() % 10,
'A' + rand() % 10,
'0' + rand() % 10,
'A' + rand() % 10,
'0' + rand() % 10];
Possession *newPossession = [[self alloc] initWithPossessionName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber];
return [newPossession autorelease];
}
I am aware that the return value should really be of type id such that id newPossession = ...
I subclassed Possession and created a class called BallGlove that included a new iVar, brandName, an NSString *
I overrode the +randomPossession in BallGlove as follows:
+(id)randomPossession
{
BallGlove *myGlove = [super randomPossession];
NSArray *brandNames = [NSArray arrayWithObjects:@"Rawlings", @"Mizuno", @"Wilson", nil];
unsigned long randomNameIndex = rand() % [brandNames count];
[myGlove setBrandName:[brandNames objectAtIndex:randomNameIndex]];
NSLog(@"myGlove is of type class: %@", [self class]);
return myGlove;
}
My question is this: Is the manner in which I overrode this class method appropriate and acceptable by the community (i.e. parallel the -init format by capturing the super implementation in a variable, manipulate the variable accordingly and then return it? My output shows that the object returned is an instance of BallGlove however, I was interested in the acceptable implementation. Thanks in advance.
Upvotes: 12
Views: 15681
Reputation: 25632
It's technically ok.
I'd propose an alternative, though. If you already have a designated public initializer on your base class (which you might want to create and call from that factory class method anyway), and then use that very initializer (or even a new one from your subclass) in your subclasses' class method.
It's not much more code, but in my opinion easier to follow and future-proof. The initializer might come handy as well at one point, but of course it's not a solution for every application.
Upvotes: 0
Reputation: 2830
Yes, it is acceptable to do your initialization like that. In fact that is how it is done in most cases. I mean, that is the reason for inheriting from a super class in the first place. You want stuff in addition to what is present in the super class. So, you insert code to whatever is specific to the inherited class and it should be done that way.
I think how you want the BallGlove
object initialized is also a factor in how you define your inherited method. The question arises on calling the Possession
init or calling the BallGlove
init (Not that creating an instance of a class is the only place to use a class method). So it comes down to the logic of creating your objects i.e. how you well you are describing BallGlove
object-are you making sure that your class method describes it in ways that fits the BallGlove
object criteria and does not become generic Possession
object. My answer is that if you can implement it right, using a parallel line of class methods is acceptable.
Also, it doesn't matter if you are returning of type Possession
in your super class because, id
can point to an object of any class type
Upvotes: 1
Reputation: 35721
The moment you override a class method you can decide to implement it with the help of the super implementation or without it. It is totally up to you. Overiding init is a completely differeent story, not only because it is an instance method but because it has a convention/contract associated with it. Keep in mind that for instance methods the Liskov Subtitution principle should not be violated.
Your overrided of the class method is perfectly fine, although I would consider overiding class methods a design smell. Although it's very well possible in Objective-C, it's not in other languages and that for a very good reason. Polymorphism as a concept is better bound to instances that can be used as substitutes for each other, whereas using class methods breaks the concept (i.e. no real subtitution). It's clever, but not necessesarily intuitive and flexible.
Upvotes: 3
Reputation: 237010
Yep, that's a perfectly sensible way to do it. There's nothing particularly different between class methods and normal methods — just that one is performed by a class and the other is performed by an instance.
Upvotes: 4