51

A quick question.

if I have a property and an ivar declared with the same name:

in the .h file:

(Reminder*)reminder;
@property(nonatomic,strong)(Reminder*)reminder;

in the .m file, should I use the ivar or the property in the init method if I'm using ARC?

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        reminder = reminder_;
    }
    return self;
}

Or should I use the property to get the benefit of the automatic reference counting like this:

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        self.reminder = reminder_;
    }
    return self;
}

I'm not sure at which point in the object's initialization the properties become accessible with the dot notation.

justin
  • 104,054
  • 14
  • 179
  • 226
Alex Stone
  • 46,408
  • 55
  • 231
  • 407
  • 4
    if you use synthesize (i guess you do) and you use a modern compiler (i guess you do because of ios5) you don't need to declare the ivar, objective-c does that automatically for you. (this is not the answer to your question, just a sidenote). – choise Nov 08 '11 at 19:49
  • This is a good thing to know, I always declared ivars for properties up to now. And yes, I do @synthesize the property with the default name. – Alex Stone Nov 08 '11 at 20:35
  • Was about to tell you the same thing as @choise. And I believe you still get the benefit of ARC regardless of whether or not you use the property. – Undeadlegion Nov 09 '11 at 11:25
  • 3
    You don't even need `@synthesize` – nielsbot Aug 30 '13 at 22:25

3 Answers3

68

Use direct access in partially constructed states, regardless of ARC:

- (id)initWithReminder:(Reminder*)reminder_ {
    self = [super init];
    if (self) {
        reminder = reminder_;
        // OR
        reminder = [reminder_ retain];
    }
    return self;
}

This is because self.whatever will trigger other side effects, such as Key-Value Observing (KVO) notifications, or maybe your class implements (explicitly) or a subclass overrides setWhatever: -- and that could expose your partially initialized instance to other APIs (including its own), which rightly assume they are dealing with a fully constructed object.

You could manually verify that a class is capable of operating in a partially initialized state, but that requires a lot maintenance and is (frankly) impractical or impossible when other people want to subclass your class. It requires a lot of time and maintenance, and there isn't substantiative benefit doing so, especially if you try to use the approach as a convention.

So the uniform manner which guarantees correctness is to use direct access in partially constructed states, and avoid using the accessors.

Note: I am using "partially constructed" because initialization is only half of the picture; -dealloc has similar caveats.

Some more detail as to why you should use direct access in partially constructed states (ARC || MRC) can be found here: Initializing a property, dot notation

Community
  • 1
  • 1
justin
  • 104,054
  • 14
  • 179
  • 226
  • 1
    I'm a bit confused by this when it comes to subclass. If we shouldn't use self.propertyName in init methods, how do you access a parent class's property inside the init method of a subclass ? using _propertyName in subclass says undeclared variable, the only solution is to use self.propertyName. Example: http://stackoverflow.com/questions/16622776/how-to-access-super-classs-variables-in-init-method – Zhang Apr 03 '14 at 08:54
  • @Zhang generally, you should avoid accessing the properties of the base class in initializers. that approach requires your derived class to know about its superclass' implementation, as well as all derived classes which could override the accessor implementations. in objc, you can actually end up calling (the uninitialized) derived class' overridden accessor methods. so you can avoid this headache/risk by: following the advice above, providing more appropriate initializers, using accessors on fully constructed instances, using less complex types (composition), convenience constructors, etc. – justin Apr 25 '14 at 16:43
  • 2
    @Zhang I think it is safe to call properties from superclass in subclass' init. By the time you reach "body" of subclass' init, superclass' init should have already finished. That means, superclass itself is (or at least should be, if written correctly) already initialized completely. Thus accessing its (= superclass') properties should be safe - even if you override the property in subclass. The problem is when you access the property in init in superclass. In such case, if you override setter in subclass, you may get there with partially initialized object. – manicaesar Dec 08 '14 at 11:29
  • @manicaesar it's not very safe; especially as complexity of class hierarchies and classes increase: http://stackoverflow.com/questions/5932677/initializing-a-property-dot-notation/5932733#5932733 -- true, one can make a provably safe design *but* who wants to verify that remains safe whenever the implementations are modified? it's complicated/tedious/error prone and doesn't buy you much. – justin Dec 09 '14 at 15:01
  • 1
    @justin ok, so when I subclass UITableViewCell and want to add to add some custom UIView as a subview to its contentView in initialization, what should I do instead of: [self.contentView addSubview:someSubview]; ? – manicaesar Dec 10 '14 at 12:56
  • @manicaesar in the larger picture, you would ideally perform such setup after all initializers have run and the instance is fully initialized. maybe that is in an `-awakeFromNib`, lazy initialization, or another stage of setup -- depends on the object. – justin Dec 10 '14 at 16:59
  • 1
    @justin If I construct my UITableViewCell subclass in code (you can not say it is forbidden), then awakeFromNib is not an option. Using lazy initialization in such case is in my opinion simple workaround of a problem. I use lazy initialization only when it is logical (e.g. when non-lazy init is bottleneck which is rather NOT the case here) - not in order to stick to some other (quite not-related) rules... But ok, I think we just have two different approaches and priorities we apply to our code :) – manicaesar Dec 11 '14 at 13:30
  • @manicaesar I provided a third, very broad option: "another stage of setup - depends on the object". Maybe that is code in the client domain, an override, a convenience constructor, property implementations, etc. - you can approach problems many ways in code. There is not one which suits every implementation ideally, and certainly too many variants for comment fields. – justin Dec 11 '14 at 13:56
5

No you shouldn't!

You can find description why here
Also apple recommend to don't do it. Read here

Kostiantyn Koval
  • 8,407
  • 1
  • 45
  • 58
0

I'm not sure at which point in the object's initialization the properties become accessible with the dot notation.

Since the dot notation is still an Objective-C method (and a C method actually under the ObjC method) the dot notation, or calling the method, is perfectly safe GIVEN the method is prepared to deal with underlying type(s) in memory in whatever state they happen to be in. The normal rule about avoiding use of an uninitiatilized (possibly) garage memory segment still would apply. Which is the strongest motivation for use of the ivar in the init.

But if your method (getter|setter) is capable of correctly using the memory segment - independent of whether it is first written to before being read - then by all means use your getter in the init method. A Lazy getter takes advantage of the assumption that a pointer it will initialize starts as 'nil' to decide on performing the initialization. If you cannot assume the initial contents of your memory then initializing the ivar might be the safest course.

Why have the rule of never using setters or getters in the init if the method is capable of operating correctly in this scenario?

user1864957
  • 81
  • 1
  • 3