3

Hi imagine I have properties in the .h file:

@property (nonatomic) NSString * myText;
@property (nonatomic) SomeClass * someObj;

Now, in the class implementation.

Say, I didn't forget to use synthesize, and I called:

@synthesize myText, someObj;

Now say in code I forget to put self before the property name (and directly refer to the ivar):

myText = @"Hello";
someObj = [[SomeClass alloc] init];

My question is: is this a problem? What problems can it result in? Or it is no big deal?

ps. Say I am using ARC.

user2054339
  • 393
  • 1
  • 6
  • 20
  • 3
    It's a mistake if you expect them to manage memory as property accessors do. (Also, there are property setters with side effects, etc...) - However, using `self.property` is **not** obligatory *if you know what you are doing.* –  Jul 27 '13 at 12:06
  • 1
    Or if you have observers against those properties. – Abizern Jul 27 '13 at 12:08
  • 2
    Or if you are accessing a lazily loaded property, such as `view` in a ViewController` – Abizern Jul 27 '13 at 12:09
  • @H2CO3: But if I am using ARC? is it still problem with memory? and finally, the only way to refer to properties it through `self` right? dot notation (I am omitting calling the getter/setters here). – user2054339 Jul 27 '13 at 12:10
  • 1
    Unlike many claim, there isn't a "recommended way". Programming is more logic that maths. You should think and, according to your situation, choose the one that you need. You don't want to use the accessor overridden by subclasses? Don't use `self.myText`. You want to initialize the property lazily? Use `self.myText`. The best is if you know what is their meaning, and you choose which one to choose according to the situation. – Ramy Al Zuhouri Jul 27 '13 at 12:47
  • @ Ramy Al Zuhouri: I agree with you more or less. That was my point, since sometimes I forget to put `self` before property names, I was wondering if something really bad would happen out of that. I think memory issues can be no problem if I am using ARC (e.g., H2CO3's comment) – user2054339 Jul 27 '13 at 12:51
  • 2
    That's why many use @synthesize someObj = _someObj. Which separates the name of the backing iVar from the property name. That way you'll easily distinguish between direct use of the iVar (which has the leading underscore) and if you forget to use self, you'll get a compiler warning. If you use autosynthesized properties, then the backing iVar has an leading underscore by default. – Abizern Jul 27 '13 at 13:56

5 Answers5

2

My question is: is this a problem?

This is called "direct ivar access". In some cases, it's not a problem, but a necessity. Initializers, dealloc, and accessors (setters/getters) are where you should be accessing self's ivars directly. In almost every other case, you would favor the accessor.

Directly accessing ivars of instances other than self should be avoided. Easy problem here is that you may read or write at an invalid address (undefined behavior), much like a C struct. When a messaged object is nil, the implementation of that message is not executed.

What problems can it result in?

Biggest two:

  • You won't get KVO notifications for these changes
  • And you are typically bypassing the implementation which provides the correct semantics (that can be justified). Semantics in this case may equate to memory management, copying, synchronization, or other consequences of a change of state. If, say, a setter is overridden, then you are bypassing any subclass override of that setter, which may leave the object in an inconsistent state.

See also: Why would you use an ivar?

Community
  • 1
  • 1
justin
  • 104,054
  • 14
  • 179
  • 226
1

For clarity, I recommend always using

self.propertyname

as opposed to

propertyname

as this removed any confusion between what variable belong to the class or have been declared locally above in the method.

To enforce this, try to avoid using @synthesize at all, which is only needed if you provide both custom getter and setter (but not one or the other)

The compiler automatically allows you to use _propertyname in the getter/setter (which is necessary to prevent recursive calls of the function)

Nick Banks
  • 111
  • 2
  • 1
    You also need to @synthesize the backing store for a readonly property if you are going to provide a getter for it – Abizern Jul 27 '13 at 15:23
  • 1
    Good answer, but the final statement may be a little confusing ("The compiler automatically allows you to use _propertyname in the getter/setter…"). The compiler will let you use `_propertyname` within the entire object, not just within the getter/setter. You *shouldn't* use `_propertyname` outside the accessors, `init`, and `dealloc`, but the compiler will allow it (it won't even provide analyzer warning). – Rob Napier Jul 27 '13 at 16:48
1

You should not access the underlying instance variables by accident, only if you plan to do so.

Unexpected side effects may be that KVO doesn't work, overriding accessor methods are not called and the copyand atomic attributes have no effect.

You don't need to use @synthesize since Xcode 4.4, if you use default synthesis the compiler does an equivalent of

@synthesize myText = _myText;

so that

_myText = @"Hello";
self->_myText = @"Hello";

are equivalent and myText = @"Hello"; results in an "undefined identifier" compiler error.

If you use just @synthesize myText the compiler does (for backward compatibility reasons):

@synthesize myText = myText;

which is error prone.

Note that there are valid reasons to use the underlying instance variables instead of the accessor - but it's bad style to do this by accident.

eik
  • 2,104
  • 12
  • 15
0

For 30 years now, the recommended practice has been:

  • use getter/setter methods or the new . operator to read and write ivars.
  • only access ivars directly when you must.
  • pick ivar names to prevent accidentally using them, unless the ivar is one that will always be accessed directly (that is why the default behaviour and convention is to prefix ivars with an underscore).

You need to access ivars directly in a few situations:

  • Manual memory management requires it. You won't need this if ARC is enabled.
  • If you are going to read the variable variable millions of times in quick succession, and you can't assign it to a temporary variable for some reason.
  • When you're working with low level C API, it probably needs a pointer to the ivar, Apples libxml2 sample code accesses ivars directly for example.
  • When you are writing the getter or setter method yourself, instead of using the default @synthesize implementation. I personally do this all the time.

Aside from these situations (and a few others), do not access ivars directly. And prefix all ivars with an underscore, to make sure you don't accidentally access them and to prevent them appearing in xcode's autocomplete/intellisense while you code.

The two main reasons for the convention are:

  • Getter/setter methods and properties can be kept around when the underlaying memory structure of your class changes. If you rename an ivar, all code that reads the ivar will break, so best to have zero code or almost no code that accesses ivars directly.
  • Subclasses can override getters and setters. They cannot override ivars. Some people think subclasses shouldn't be allowed to override getters and setters - these people are wrong. Being able to override things is the entire point of creating a subclass.
  • Fundamental features like KVC and KVO can fall apart if you access ivars directly.

Of course, you can do whatever you want. But the convention has been around for decades now and it works. There is no reason not to follow it.

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110
-1

Contrary to what other answers seem to agree upon, I would recommend to always use direct ivar access unless you are very clear about what you are doing.

My reasoning is simple:

  1. With ARC, it's not even more complicated to use direct property access, just assign a value to the ivar and ARC takes care of the memory management.

  2. (And this is my main point:) Property accessors may have side-effects.
    This is not only true for property accessors you write, but may also be true for subclasses of the class you are implementing.
    Now these accessors defined in subclasses may very well rely on state that the subclass sets up in it's initializer, which has not executed at this point, so you calling those accessors might lead to anything from undefined state of your object to your application throwing exceptions and crashing.

Now, not every class may be designed to be subclassed, but I think it's better to just use one style everywhere instead of being inconsistent depending on the class you are currently writing.

On a side note: I would also recommend to prefix the name of every ivar with an _, as the compiler will do automatically for your properties when you don't @synthesize them.

Ahti
  • 1,420
  • 1
  • 11
  • 20
  • ARC doesn't change anything about how Obj-C works, all it does is write some code on your behalf at compile time, code should be written the same regardless of whether ARC is enabled or not. Re: "Property accessors may have side-effects." — The whole point of accessors is to make side-effects possible. That is a feature, not something to avoid. A subclass must always know exactly how the parent class works and it is responsible for making sure it doesn't break anything. – Abhi Beckert Sep 08 '13 at 09:57