Why shoudn't I use accessor methods in init me

2020-06-16 09:03发布

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 ?

4条回答
Ridiculous、
2楼-- · 2020-06-16 09:21

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.

查看更多
仙女界的扛把子
3楼-- · 2020-06-16 09:26

just from an OOP point of view (since I have no experience with objective-c), you would not use methods of the object which is currently being constructed. This is possible in some languages, but you already have access to the private variables. The object construction isn't completed yet, so it isn't ready to be operated on. Once the object is constructed it is in a known good state (or so it is assumed) and it can perform.

查看更多
霸刀☆藐视天下
4楼-- · 2020-06-16 09:32

In modern day objective C, you SHOULD be able to use accessor methods within init. Compiler faults will RARELY if ALMOST NEVER happen

查看更多
淡お忘
5楼-- · 2020-06-16 09:33

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

查看更多
登录 后发表回答