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.