Objective-C 2.0 offers some neat new features that make life easier for programmers. If you’re familiar with Java programming you are used to declaring getter and setter functions to access the instance variables of a class, and similarly in C#, you have the ability to declare property functions, get and set, which do the same thing, and have them be auto-implemented, i.e. you just have to let the compiler know you want a property accessor generated for a particular instance variable.
In Objective-C you can achieve the same task, i.e. implement automatic property getter and setter functions, using the new @property
and @synthesize
compiler directives, which are part of the Declared Properties feature, @property
belonging to the Property Declaration Directives, and @synthesize
being part of the Property Implementation Directives.
Wrapping your class instance variables, i.e. object’s properties in Objective-C, adheres to the principle of encapsulation of data which lets you exercise control over how particular properties can be interacted with, letting you range check passed in values, or perform secondary functions before assigning the new value.
The following example program adds Declared Properties, also known as property getter & setter functions, by using the appropriate compiler directives @property
and @synthesize
, to automatically generate functions to read and write the instance variables.
One of the property functions will treat the instance variable as read-only, using the readonly
modifier attribute, meaning that within the class, direct access to the instance variable is via normal means, i.e. directly accessing the instance variable, and outside of the class the instance variable is read-only and its value cannot be altered. The other properties of the class use the readwrite
modifier attribute to indicate that both getter and setter functions should be generated.
I use the notation of m_
on the instance variable names, a throwback to my days of C++ programming, to identify instance variables separately from their property accessor functions.
#import <Foundation/Foundation.h>
// declare the interface for the telepgrah message
@interface TelegraphMessage : NSObject
// add some instance variables that describe a standard telegraph message
NSString * m_operatorName;
NSString * m_message;
NSDate * m_date;
int m_cost;
// declare the automatically implemented property accessors
// the telegraph operators name can only be read by external code
@property(retain, readonly) NSString *operatorName;
// the message, date and cost can be read or written by external code
@property(copy, readwrite) NSString *message;
@property(retain, readwrite) NSDate *date;
@property(assign, readwrite) int cost;
@end
// define the implementation for the telegraph message
@implementation TelegraphMessage
// automatically generate the property accessors for each property
// name, connecting the property to the instance variable
@synthesize operatorName = m_operatorName;
@synthesize message = m_message;
@synthesize date = m_date;
@synthesize cost = m_cost;
// define the default constructor
- (id) init
{
// hard-code the telepgraph operator's name, but this could easily
// come from a database, or some other data source
m_operatorName = @"Charlie";
return self;
}
@end
int main (int argc, const char * argv[])
{
// standard Foundation housekeeping
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// define a telegraph message to send
TelegraphMessage *telegraph = [TelegraphMessage new];
telegraph.message = @"Hello World!";
telegraph.date = [NSDate date];
telegraph.cost = 10;
// output the properties of the telepgrah message
NSLog(@"Telegraph Operator: %@", telegraph.operatorName);
NSLog(@"Telegraph Message: %@", telegraph.message);
NSLog(@"Telegraph Date: %@", telegraph.date);
NSLog(@"Telegraph Cost: %d", telegraph.cost);
// standard Foundation housekeeping
[pool drain];
return 0;
}
Telegraph Operator: Charlie
Telegraph Message: Hello World!
Telegraph Date: 2010-10-11 14:05:39 -0700
Telegraph Cost: 10
The program output shows that the four instance variables are indeed accessed through the automatically implemented property accessors.
The first property, the telegraph operator’s name, which is read-only, is initialised during the class constructor to a default value which could easily be changed so that accessing the read-only property accessor could retrieve the operator’s name from a database or perform some calculation to decode the telegraph operator’s name by passing it through a super-secret cryptographic algorithm first.
The remaining three properties, message, date and cost, are all properties that can be read and written easily enough.
The ability to generate simplistic getter and setter functions, turning your instance variables in to properties, is a useful feature to have in any language. Anything that cuts down on verbose pages of code that do nothing very much, e.g. the functions of getPropertyX
and setPropertyX
that are frequently found scattered throughout Java classes.
There is still a need, in some cases, to hand-code a particular property accessor function based on the need to perform a calculation, or verify the values passed in before storing them, but most cases, automatically implementing the properties reduces code clutter and makes the intention of the original programmer clear to those programmers coming after them who now have to read the code and determine how something was intended to be used.
It’s always the little things about a particular programming language that cause the most frustration and so the ability to automatically generate class property getter and setter methods in Objective-C is a hugely useful feature that takes much of the drudgery out of declaring and exposing class variables.