Benedict's Soapbox

Defining an Objective-C @property as Publicly readonly and Privately readwrite

Often a property needs to be publicly read only but privately it needs to be read/write. The Objective-C 2.0 @property syntax does not provide a means to do this, but it is possible to do so without resorting to accessing ivar directly by canny use of categories. Here’s how:

Person.h


@interface Person : NSObject  
{  
}

-(void)eatChocolateCake;

@end


@interface Person (ReadOnlyProperties) //the category name is arbitrary, but it cannot be anonymous  
@property(readonly, nonatomic) NSString *mood;  
@end  

Person.m


@interface Person () //this category should be anonymous so it is coalesced with the base @interface declaration  
@property(readwrite, nonatomic, retain) NSString *mood;  
@end

@implementation Person

@synthesize mood = mood_;

-(id)init  
{  
self = [super init];  
if (self)  
{  
mood_ = @"hungry";  
}  
return self;  
}

-(void)dealloc  
{  
[mood_ release];  
[super dealloc];  
}

-(void)eatChocolateCake  
{  
self.mood = @"happy";  
}

@end  

The person class in use

Person *frank = [[Person new] autorelease];

NSLog(@"Frank is feeling %@", frank.mood); //Frank is feeling hungry  
[frank eatChocolateCake];  
NSLog(@"Frank is feeling %@", frank.mood); //Frank is feeling happy

//frank.mood = @"sleepy"; //this line causes a compiler error  
NSLog(@"Frank is feeling %@", frank.mood); //Frank is feeling happy