Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why shoudn't I use accessor methods in init methods

From Apple documentation about Memory Management :

The only places you shouldn’t use accessor methods to set an instance variable are in init methods and dealloc. To initialize a counter object with a number object representing zero, you might implement an init method as follows:

To allow a counter to be initialized with a count other than zero, you might implement an initWithCount: method as follows:

- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        count = [startingCount copy];
    }
    return self;
}

Why not ?

like image 440
Pierre Valade Avatar asked Aug 06 '10 13:08

Pierre Valade


2 Answers

See my answer to this question.

The main reason why is because a subclass might override your accessors and do something different. The subclass's accessors might assume a fully initialised object i.e. that all the code in the subclass's init method has run. In fact, none of it has when your init method is running. Similarly, the subclass's accessors may depend on the subclass's dealloc method not having run. This is clearly false when your dealloc method is running.

To expand on your example, if you had instead done

- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        [self setCount: [startingCount copy]];
    }
    return self;
}

but a subclass had overridden setCount: to do something other than set your count variable, you could be in trouble.

like image 98
JeremyP Avatar answered Nov 02 '22 23:11

JeremyP


JeremyP made a good point. Since the syntax of setter invocation always involves "self", whose type is determined at runtime, so a subclass instance could call its overridden version of setter, if "self" is truly a subclass object...

However, there are some cases in which you must use the setter in an initializer. This is when the instance variable is declared within a superclass; you can NOT access the instance variable directly anyway, so you must use the setter.

Another situation is when the property uses lazy initialization. In this case, you have to go via the getter; if you don’t, the instance variable will never get a chance to be initialized. For example, the EOCPerson class might have a property to give access to a complex object repre- senting each person’s brain. If this property is infrequently accessed and expensive to set up, you might initialize it lazily in the getter, like this:

- (EOCBrain*)brain { if (!_brain) {
        _brain = [Brain new];
    }
return _brain; }

If you were to access the instance variable directly and the getter had not been called yet, brain would not have been set up, and you would have to call the accessor for all accesses to the brain property.

-- Matt Galloway's EOC book Item7

like image 36
J-Q Avatar answered Nov 03 '22 01:11

J-Q