Objective-C 2.0 Accessors & Memory Management
Quite often, you may have simple setter methods that need to do a just a tiny bit of work before or after setting an instance variable. For example, maybe you need to redraw something after setting the property of an object. So, instead of writing this:
[self setBackgroundColor:[NSColor blueColor]];
[view setBackgroundColor:[NSColor blueColor]];
You’d probably want to move the relevant code to your -setBackgroundColor:
accessor instead:
- (void)setBackgroundColor:(NSColor*)color
{
// Assuming that _backgroundColor is the ivar you want to set
if(_backgroundColor != color)
{
[_backgroundColor release];
_backgroundColor = [color retain];
// Update the view's background color to reflect the change
[view setBackgroundColor:_backgroundColor];
}
}
Then you can simply call -setBackgroundColor:
and expect it all to work nicely:
// -setBackgroundColor: updates the view's background color
// automatically now
[self setBackgroundColor:[NSColor blueColor]];
(You could use Key-Value Observing to do this, but I generally avoid KVO for simple intra-class property dependencies like this. I don’t think the overhead of maintaining all the KVC dependencies and KVO-related methods is worth the cost.)
Of course, the above method requires that you write all that stupid boilerplate memory management code in the accessor. Instead of doing that, I tend to declare a private _backgroundColor
property in the class, @synthesize
a method for the private property, and then use the private property’s generated accessors instead:
@interface MyClass ()
// Declare a _private_ _backgroundColor property (thus the underscore
// in front, and why it's declared in a class continuation rather than
// in the public header)
@property (copy, setter=_setBackgroundColor:) NSColor* _backgroundColor;
@end
//
@implementation MyClass
@synthesize _backgroundColor;
- (NSColor*)backgroundColor
{
return [self _backgroundColor];
}
- (void)setBackgroundColor:(NSColor*)color
{
// Use the private property to set the background colour, so it
// handles the memory management bollocks
[self _setBackgroundColor:color];
[view setBackgroundColor:[self _backgroundColor]];
}
...
@end
With that technique, it’s possible to completely directly setting ivars, and thus avoid -retain
and -release
altogether. (You’ll still need to use -autorelease
at various times, of course, but that’s reasonably rare.) We have some source code files that are well over 2000 lines of code without a single explicit [_ivar retain];
or [_ivar release];
call thanks to this technique. (Yeah, 2000 lines is also large and the class needs refactoring, but that’s another story.)
Of course, you could just use garbage collection which avoids 99% of the need for this bollocks:
- (void)setBackgroundColor:(NSColor*)color
{
// Yay GC!
self->_backgroundColor = color;
[view setBackgroundColor:self->_backgroundColor];
}
But plenty of us don’t have that luxury yet. (iPhone, ahem.)
git & less
For the UNIX users out there who use the git revision control system with the oldskool less pager, try adding the following to your ~/.gitconfig
file:
[core]
# search for core.pager in
# <http://www.kernel.org/pub/software/scm/git/docs/git-config.html>
# to see why we use this convoluted syntax
pager = less -$LESS -SFRX -SR +'/^---'
That’ll launch less with three options set:
-S
: chops long lines rather than folding them (personal preference),-R
: permits ANSI colour escape sequences so that git’s diff colouring still works, and+'/^---'
: sets the default search regex to^---
(find---
at the beginning of the line), so that you can easily skip to the next file in your pager with then
key.
The last one’s the handy tip. I browse commits using git diff
before committing them, and like being able to jump quickly back and forth between files. Alas, since less is a dumb pager and doesn’t understand the semantics of diff patches, we simply set the find regex to ^---
, which does what we want.
Of course, feel free to change the options to your heart’s content. See the less(1)
manpage for the gory details.
As the comment in the configuration file says, you’ll need to use the convoluted less -$LESS -SFRX
prefix due to interesting git behaviour with the LESS
environment variable:
Note that git sets the LESS environment variable to
FRSX
if it is unset when it runs the pager. One can change these settings by setting theLESS
variable to some other value. Alternately, these settings can be overridden on a project or global basis by setting thecore.pager
option. Settingcore.pager
has no affect on theLESS
environment variable behaviour above, so if you want to override git’s default settings this way, you need to be explicit. For example, to disable theS
option in a backward compatible manner, setcore.pager
to"less -+$LESS -FRX"
. This will be passed to the shell by git, which will translate the final command to"LESS=FRSX less -+FRSX -FRX"
.
(And sure, I could switch to using a different pager, but I’ve been using less for more than a decade. Yep, I know all about Emacs & Vim’s diff-mode and Changes.app. It’s hard to break old habits.)