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 thenkey.
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
FRSXif it is unset when it runs the pager. One can change these settings by setting theLESSvariable to some other value. Alternately, these settings can be overridden on a project or global basis by setting thecore.pageroption. Settingcore.pagerhas no affect on theLESSenvironment variable behaviour above, so if you want to override git’s default settings this way, you need to be explicit. For example, to disable theSoption in a backward compatible manner, setcore.pagerto"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.)