3 Tips on Auto Synthesized Properties
Ha ha! You fool! You fell victim to one of the classic blunders, the most famous of which is “never get involved in a land war in Asia.” But only slightly less well-known is this: “Never have an auto-synthesized property and an instance variable with the same name when death is on the line!”—Vizzini
At work, my team decided to drop support for iOS 4. Most of our customers have upgraded to iOS 5.1. Surprisingly, very few are still using iOS 5.0. I guess over-the-air upgrades are working really well for people.
Our app is old. In some places we still checked if the user had upgraded to iOS 3 yet. :) My team spent the week on cleanup and paying down technical debt. My job was to:
- Convert to using object literals for arrays, dictionaries and numbers.
- Switch all of our instance variables to properties.
I love shortening and removing code without losing functionality. The first two tasks went fairly quickly. But I…uh…learned a lot while tackling number three.
You can declare an instance variable in an
@interfaceblock — either the public interface in the
.hfile or the private interface in the
.mfile. You can also declare one in the
@implementationblock in the
.mfile. Or all three at once.
You can mix instance variables, properties and auto-synthesized properties. But auto-synthesized properties are so much nicer: less code, less maintenance, less boilerplate typing. Here are 3 tips to help you use properties more effectively.
1. Deal With Read-Only Properties
An auto-synthesized property generates an instance variable with the same name as the property except prefixed with an underscore. This is great because it’s clear whether you’re using the property (
self.myprop) or the instance variable (
_myprop). Using the bare name (
myprop) doesn’t even compile, so you limit the confusion and bugs caused by accidental mistypes.
Auto-synthesized properties create their own getter and setter methods (avoiding some unnecessary typing). You can implement your own getter and/or setter, in which case those methods are not automatically generated. The instance variable (
_myprop) is still synthesized.
However, if your property is
readonlyAND you implement your own getter method, then an instance variable is not synthesized. I suspect this is to allow for a named property that is dynamically calculated. In any case, if you would like an instance variable, you can force it to be synthesized by either:
@synthesize myprop = _myprop;in your
- Redeclaring the property as
readwritein your private
The second option works like inheritance in that you can redeclare a property as less-restrictive but not the other way. Redeclaring a public
readwriteproperty as privately
readonlyisn’t possible, though why you’d want to do that remains a mystery.
2. Avoid Instance Variables
It is a Bad Thing™ to have both an auto-synthesized property and an instance variable declared with the same name.
self.myprop = 1uses the auto-synthesized instance variable
myprop = 1uses the declared instance variable
_myprop= 1 uses the auto-synthesized instance variable
Since you end up with two instance variables, when you probably intended to have only one, doing this can cause lots of unexpected bugs and problems. Better to avoid declaring instance variables for your synthesized properties.
It is a Worse Thing™ to have two auto-synthesized properties of the same name with one prefixed with an underscore.@property myprop; @property _myprop;
This causes problems because
self._mypropis different than
_mypropwhen you really should have used
__myprop, making you start to wonder about your own sanity. This doesn’t seem like it would happen much, but it can if you are importing several
.hfiles, one of which uses underscores in its property names.
So don’t do that. :)
3. Use Instance Variables Correctly
In most cases, it’s best to stick with using the property (
self.myprop) in your code. However, it’s important to use the instance variable (
_myprop) in two cases:
- In your
init:methods to avoid possible side-effects if you implement your own setter later, and
- In your custom getter and setter methods to avoid infinite recursion (always nice).
Auto-synthesized properties are great. Not quite as awesome as ARC, but close.