Changing Default Property Names

Last week we looked at declaring atomic and nonatomic properties. I promised to talk about writing a thread safe getter this week, but I'm pressed for time today so I'm going to shoe horn in another short topic instead.

When you declare a property in a class, the getter has the same name as the property, while the setter is the capitalized property name with set prepended. For illustration, here is a User class with a property named active:

@interface User : NSObject {
  BOOL active;
}
@property BOOL active;

@end


@implementation User

@synthesize active;

@end

The compiler will generate a getter method named active and a setter method named setActive. Sometimes the default method names aren't exactly what you want; for instance, it's a common convention that getters for BOOL properties be prefixed with is. In the case of our User class, we would like to have the getter named isActive.

The @property directive has two attributes to do just this: getter=name and setter=name. Just like the other attributes of @property, getter and setter are placed in parentheses after the @property directive and before the property type and name. So the active property in our example would look like:

@interface User : NSObject {
  BOOL active;
}
@property (getter=isActive) BOOL active;

@end

@implementation User

@synthesize active;

@end

And usage the active property now looks like:

// example use of isActive getter
User *user = [[User alloc] init];

// getter/setter called as methods
if ( ! [user isActive] ) {
  [user setActive:YES];
}

// getter/setter called with dot syntax
if (user.isActive) {
  user.active = NO;
}

We'll take a closer look at dot syntax in the near future, but basically when the compiler sees code like this:

if ( user.isActive ) {
  user.active = NO;
}

it translates it into this:

if ( [user isActive] ) {
  [user setActive:NO];
}

Dot syntax is complementary to properties, but is separate and unaware of them. When translating a setter call in dot syntax to the corresponding method call, the compiler always looks for a method beginning with set. If you change your setter name to something different, you'll see a compiler error like

object cannot be set - either readonly property or no setter found

or

request for member 'setter name' in something not a structure or union

if you call it using dot syntax. So if we rename the setter for the active property to makeActive instead of the default setActive:

@interface User : NSObject {
  BOOL active;
}
@property (getter=isActive, setter=makeActive) BOOL active;

@end

then using method call syntax, we can now do this:

if ( [user isActive] ) {
  [user makeActive:NO];
}

but because the compiler expects setters to begin with set, using dot syntax generates an error:

if (user.isActive) {
  user.makeActive = NO; // ERROR: request for member 'makeActive' 
                               // in something not a structure or union
}

In general you should follow the standard conventions and use the default getter and setter names; it's less work for you and your code is easier for others to understand.

Next week, we'll look at the thread safety of getters that return retained objects.