Brian Palma
Brian Palma

Reputation: 641

How do I properly override a class method in an Objective-C in a subclass?

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

Answers (4)

Eiko
Eiko

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

MadhavanRP
MadhavanRP

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

Johannes Rudolph
Johannes Rudolph

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

Chuck
Chuck

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

Related Questions