DRYing your instance variables

In my last post about understanding the Objective-C self object I got into a discussion on the use of properties when accessing instance variables. I should have also mentioned that it is also possible to completely avoid declaring the instance variables. The example I used was as follows:

@interface RootViewController : UITableViewController {
  NSDate *timestamp;
}
@property (nonatomic, retain) NSDate *timestamp;

If you look at this code it clearly contains some duplication. The fact that timestamp is a pointer to an NSDate object is defined in the body of the class interface and then repeated in the @property declaration. The Don’t Repeat Yourself (DRY) principle of software development is aimed at ensuring that things are defined once and only once. This is not only to save typing but also as a way of reducing dependencies between code and making it easier to modify in the future. Luckily there is a way to DRY this piece of code.

Instance Variable Synthesis

The @synthesize statement placed in the implementation block of a class instructs the compiler to automatically generate any missing getter and setter accessor methods. This clearly saves a lot of tedious typing and is in itself a huge help in keeping Objective-C code dry. The example that I looked at in the previous post had the following getter and setter for the timestamp instance variable:

- (NSDate *)timestamp {
  return timestamp;
}

- (void)setTimestamp:(NSDate *)newValue {
  if (timestamp != newValue)
  {
    [timestamp release];
    timestamp = [newValue retain];
  }
}

Having to write this sort of code for every instance variable would be a pain. The @synthesize statement instructs the compiler to take care of this work for us and ensures the setter is generated correctly based on whether we specify assign, retain or copy for the setter.

What I think is less well known is that the compiler will also automatically synthesize the instance variables if required. This feature was included with what Apple describes as the “modern Objective-C Runtime” which was introduced with Objective-C 2.0 and is used by iOS and 64-bit Mac OS X programs from v10.5 onwards. The previous example can simply be written as follows:

@interface RootViewController : UITableViewController {
}

@property (nonatomic, retain) NSDate *timestamp;

Now when the compiler synthesizes the getter and setter methods it will also synthesize the instance variable. Note that you can still specify that the property and instance variable use a different name if you prefer:

@synthesize timestamp=_timestamp;

Using this approach removes the code duplication in the definition of the instance variable but you must use the synthesize statement to ensure the instance variable is created. Since the synthesize statement will only create any absent accessor methods or instance variables you can still create your own getter or setter methods if you need to do something special.