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
anIntegerinstead ofaIntegeras the parameter names for the methods. - It will
copyrather thanretainvalue 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,volatileetc) are ignored correctly. - It will emit Xcode-specific
#pragma markplaces 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.mimplementation 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.