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.)