MNY
MNY

Reputation: 1536

When overriding `init` method, why it is important to define it again?

I had an exercise to override init method, so I need to create an init method that will set some attributes as well.

My question is: why do I need to define the original init method as well? in case that the new init method won't work?

This is my .h file:

#import <Foundation/Foundation.h>

#import "XYPoint.h"

@interface Rectangle: NSObject

@property float width, height, tx, ty;

-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
-(void) translate: (XYPoint *) point;
-(id) initWithWidth:(int) w andHeight:(int) h;
-(id) init;

@end

And .m (only the init methods):

-(id) initWithWidth:(int)w andHeight:(int)h
{
    self = [super init];

    if (self)
    {
        [self setWidth:w andHeight:h];
    }

    return self;
}

-(id) init
{
    return [self initWithWidth:0 andHeight:0];
}

I know that it is good this way, but if someone can explain me why is that I would be appreciated.

Upvotes: 4

Views: 6798

Answers (2)

Anurag
Anurag

Reputation: 141879

The idea is to have a central point of initialization for your object instead of sprinkling the initialization of variables throughout each init method.

Your particular example doesn't do much justice to this pattern because you're initializing a Rectangle with 0 width and 0 height, and the default NSObject implementation resets the memory for all instance variables to zero by default, and your initWithWidth:andHeight: method does the same. However, suppose that, you were allocating unit rectangles (width 1, height 1) by default when a Rectangle object was created using,

[[Rectangle alloc] init]

then instead of doing this,

- (id)initWithWidth:(int)width andHeight:(int)height {
    self = [super init];
    if (self) {
        [self setWidth:width andHeight:height];
    }
    return self;
}

- (id)init {
    self = [super init];
    if (self) {
        [self setWidth:1 andHeight:1];
    }
    return self.
}

you're centralizing the point of initialization by just doing,

- (id)initWithWidth:(int)width andHeight:(int)height {
    self = [super init];
    if (self) {
        [self setWidth:w andHeight:h];
    }
    return self;
}

- (id)init {
    return [self initWithWidth:1 andHeight:1];
}

This also goes hand in hand with the principle of DRY a.k.a. Don't Repeat Yourself.

This is a trivial example, however, in most real-world objects, you might have a much more complicated setup with notification registration, KVO registration, etc., and then it becomes absolutely crucial that your centralize all that initialization logic.

Upvotes: 5

Jasper Blues
Jasper Blues

Reputation: 28766

You don't have do. You generally have one initializer that calls super (self = [super initWithXX]) and the others defer to that one.

In your specific example above its a good idea because initWithWidth:andHeight is acting as the main initializer, so if you call the default what ever code that needs to run in the main initializer will get called.

Btw: Use of the word 'and' in your initializer parameters is a little archaic by modern Objective-C conventions.

Upvotes: 2

Related Questions