Objective-C Accessors
I like Objective-C. It’s a nice language. However, having to write accessor methods all day is boring, error-prone, and a pain in the ass:
- (NSFoo*) foo
{
return foo;
}
- (void) setFoo:(NSFoo* newFoo)
{
[foo autorelease];
foo = [newFoo retain];
}
I mean, c’mon. This is Objective-C we’re talking about, not Java or C++. However, until Objective-C 2.0’s property support hits the streets (which, unfortunately, will only be supported on Mac OS X 10.5 and later as far as I know), you really have to write these dumb-ass accessors to, well, access properties in your objects correctly. You don’t need to write accessors thanks to the magic of Cocoa’s Key-Value Coding, but it just feels wrong to access instance variables using strings as keys. I mean, ugh—one typo in the string and you’ve got yourself a problem. Death to dynamic typing when it’s totally unnecessary.
As such, I got totally fed up with this and wrote a little script to generate accessor methods. I’m normally not a fan of code generation, but in this case, the code generation’s actually designed to be one-shot, and it doesn’t alter the ever-picky build process. It’s meant to be used in Xcode, although you can run it via the commandline too if you like.
Given the following input:
int integerThing;
NSString* _stringThing;
IBOutlet NSWindow* window;
It will spit out the following:
#pragma mark Accessors
- (int) integerThing;
- (void) setIntegerThing:(int)anIntegerThing;
- (NSString*) stringThing;
- (void) setStringThing:(NSString*)aStringThing;
- (NSWindow*) window;
- (void) setWindow:(NSWindow*)aWindow;
%%%{PBXSelection}%%%#pragma mark Accessors
- (int) integerThing
{
return integerThing;
}
- (void) setIntegerThing:(int)anIntegerThing
{
integerThing = anIntegerThing;
}
- (NSString*) stringThing
{
return _stringThing;
}
- (void) setStringThing:(NSString*)aStringThing
{
[_stringThing autorelease];
_stringThing = [aStringThing copy];
}
- (NSWindow*) window
{
return window;
}
- (void) setWindow:(NSWindow*)aWindow
{
[window autorelease];
window = [aWindow retain];
}
There’s a couple of dandy features in the script that I find useful, all of which are demonstrated in the above output:
- It will detect whether your instance variables start with a vowel, and write out
anInteger
instead ofaInteger
as the parameter names for the methods. - It will
copy
rather thanretain
value classes such as NSStrings and NSNumbers, as God intended. - For all you gumbies who prefix your instance variables with a leading underscore, it will correctly recognise that and not prefix your accessor methods with an underscore.1
- IBOutlet and a few other type qualifiers (
__weak
,__strong
,volatile
etc) are ignored correctly. - It will emit Xcode-specific
#pragma mark
places to make the method navigator control a little more useful. - It will emit Xcode-specific
%%%{PBXSelection}%%%
markers so that the accessor methods meant to go into your.m
implementation file are automatically selected, ready for a cut-and-paste.
Download the objc-make-accessors
script and throw it into your “~/Library/Application Support/Apple/Developer Tools/Scripts” folder. If you don’t have one yet:
mkdir -p ~/Library/"Application Support"/Apple/Developer Tools/Scripts/10-Scripts
ln -sf "/Library/Application Support/Apple/Developer Tools/Scripts/10-User Scripts/99-resetMenu.sh" ~/Library/"Application Support"/Apple/Developer Tools/Scripts/10-Scripts/
cp ~/Desktop/objc-make-accessors ~/Library/"Application Support"/Apple/Developer Tools/Scripts/10-Scripts/
Done. You should now have a Scripts menu in Xcode with a new menu item named “IVars to Accessor Methods”. Have fun.
1 Note that older versions of the Cocoa Coding Guidelines specified that prefixing instance variables with underscores is an Apple-only convention and you should not do this in your own classes. Now the guidelines just don’t mention anything about this issue, but I still dislike it because putting underscores every time you access an instance variable really lowers code readability.