Much of the mundane coding we used to do when setting up ivars and properties can now be completely eliminated, but you should understand why.
In the most recent releases of XCode, Apple has made some interesting improvements on how the LLVM compiler handles declared properties. These improvements have resulted in visible changes to the way properties now appear in project templates, code auto-generated by the IDE, and in Apple's sample code, some of which may now be testing your understanding of what properties are and how they actually work. So before just blindly jumping in and using automatically synthesized properties, it's worth taking a moment to understand exactly what's going on under the covers.
Properties vs. Instance Variables
First and foremost, properties are not the same as instance variables (ivars). Instance variables hold information about the various attributes of an object, such as a player's name or score in a game app. Properties are most often backed by ivars, though they do not have to be.
When you declare a property, you are essentially declaring accessor methods, which are used to set and retrieve (get) a property's value. Most often you use the @synthesize statement to tell the compiler to automatically generate these methods, but you can also write them yourself when very specific behavior is desired. It's therefore very important to keep the difference between properties and ivars clear in your mind.
To illustrate, many beginning iOS books and tutorials often show something like this in the header (.h) file:
This is followed by this code in the implementation (.m) file:
What's not immediately obvious to the new IOS programmer is that playerName is both the name of an ivar in the interface definition and the name of the property declared in the @property statement, but they are not the same thing. Because both the names and the types happen to match, the compiler will automatically assign the ivar to back the property when it synthesizes the accessor methods, which look similar to this (in pre-ARC days):
We can even use XCode to observe the difference. If we look at the @synthesize statement, XCode shows that playerName is a property:
But in the setter method, we see that it's an ivar:
Generally speaking, unless you have very specific reason not to do so, ivars should be accessed using their property methods rather than directly so that any special logic, such as bounds checking, etc. gets executed. A setter property might perform other custom logic besides just changing the value of the ivar. But if both the ivar and the property have the same name, how do you determine which one you are referencing?This is where the self keyword comes into play. By prefixing playerName with self. you will access the property; without it you will directly reference the ivar.
This may not seem important, but suppose you have a getter method that does special processing such as this:
The player's skill level determines an array of enemies to be fought. Let's see what happens when we run the following code:
We get the following results:
The first NSLog statement references the enemyArray ivar directly. New iOS programmers might expect this to return a value of 2, however at this point enemyArray has not been initialized and is nil, so sending the count message to it results in a 0, and we seemingly have no enemies to fight.
Because the second NSLog statement references the self.enemyArray property, the accessor method is called to instantiate the value of the enemyArray ivar. When we now reference the ivar directly in the third NSLog statement, we get the value we were expecting.
The take-away is that if you are not careful to access ivars through their properties, you can get unexpected results and introduce subtle errors that may be difficult to track down later.
A better way
One of the recent improvements in XCode is the focus on the use of the underscore character as a convention for naming instance variables. The goal is to promote code readability while helping to avoid the mistake of accidentally accessing an instance variable instead of its property. Technically speaking, this was possible before Apple officially made the switch in its documentation, but with XCode 4.4 it has become the preferred way, and is much more visibly present. Using this convention, our header code now looks like this:
And our implementation code looks like this:
Using the underscore now makes it quite clear when the instance variable is being referenced. Having this much now under our belts, we can now appreciate and understand the automatic synthesis of properties.
With automatic synthesis, it is no longer necessary to specifically declare backing ivars or write the @synthesize statement. When the compiler finds a @property statement, it will do both on our behalf using the guidelines we've just reviewed. So all we need to do is declare a property like this:
And the compiler will automatically declare an ivar named _playerName, and execute a @synthesize statement to tie them together like this:
Neither the declaration of the ivar or the synthesize statement will appear in your code; it is simply added in at compile time.
That is all there is to understanding automatic synthesis. While it may not seem like much of big deal, the upshot is that much of the mundane coding we used to do when setting up ivars and properties can now be completely eliminated. We can declare properties in one simple statement and move on! And since you now understand what's going on behind the scenes, you can do so with confidence.