Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C multiple nested initWith for a custom class

I'm pretty new to Objective-C and I have a question.

I have created a custom class and tried to create overloads for Initialization:

- (id)init
{
    if (self = [super init]) {
        [self setIsCurrentCar:NO];
    }
    return self;
}

-(id) initWithID:(NSInteger)id {
    if(self = [self init]) {
        [self setID:id];
    }
    return self;
}

-(id) initWithID:(NSInteger)id CarYear:(NSString *)year {
    if(self = [self initWithID:id]) {
        [self setCarYear:year];
    }
    return self;
}

Let's say at one point, I call the -(id) initWithIDCarYear method.

I'd like to know the code above is structurally correct.

  • In this code, self is set for 3 times. Is there a better solution?
  • Do I have memory leak in this code? (using ARC)
  • Do I have to check for if(self = ...) always or it is a redundant code?

Thank you

@Edit Is the following code better?

-(id) initWithID:(NSInteger)id CarYear:(NSString *)year {
    if (self = [super init]) {
        [self setIsCurrentCar:NO];
        [self setID:id];
        [self setCarYear:year];
    }
    return self;
}
like image 214
NarbehM Avatar asked Dec 21 '12 19:12

NarbehM


2 Answers

While your code is ok, i would structure the init-calls in the reverse order, where the most detailed one is the designated initializer and the more general ones would bubble some default values up:

-(id) initWithID:(NSInteger)id 
         CarYear:(NSString *)year 
{
    if(self = [super init]) {
        _year = year;
        _id = id;
    }
    return self;
}

-(id)initWithID:(NSInteger)id 
{
    return [self initWithID:id CarYear:@"unset"];
}

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

if calling one of the more general initializer would generate an illegal state, you could instead throw an error to prohibit using it.

let's assume, a car needs to have a ID, but not a year. It would be ok to use initWithID but using init would lead to an inconsistent state, so we want to force not to use it:

-(id)init 
{
    [NSException raise:NSInternalInconsistencyException 
                format:@"You must use -initWithID: or -initWithID:CarYear:", NSStringFromSelector(_cmd)];
    return nil;
}

  • In this code, self is set for 3 times. Is there a better solution?

see above

  • Do I have memory leak in this code? (using ARC)

No, everything is fine

  • Do I have to check for if(self = ...) always or it is a redundant code?

As I showed you: you can call different init methods in a chain. just the last in that chain needs to perform that.


-(id) initWithID:(NSInteger)id CarYear:(NSString *)year {
    if (self = [super init]) {
        [self setIsCurrentCar:NO];
        [self setID:id];
        [self setCarYear:year];
    }
    return self;
}

You should not use setters on self in init-methods, see Apple's docs.

like image 131
vikingosegundo Avatar answered Oct 28 '22 10:10

vikingosegundo


I'd like to know the code above is structurally correct.

Yes. I don't see any problem with it.

In this code, self is set for 3 times. Is there a better solution?

That's pretty normal. I wouldn't bother changing that.

Do I have memory leak in this code? (using ARC)

No.

Do I have to check for if (self = ...) always or it is a redundant code?

You don't have to, but you definitely should. See this question for details.

like image 34
DrummerB Avatar answered Oct 28 '22 11:10

DrummerB