Automatically releasing retained @property values
January 12, 2010 04:03 PM
| Cocoa, Development, Mac
| Permalink
I subscribe to the opinion, that setters should not be called in constructors nor in destructors. This negates some of the benefits of @synthesize accessors. Indeed, one needs to keep the dealloc method in sync with the setter semantics. Our dealloc methods thus look like this:
- (void)dealloc
{
// Retained properties
[_firstProperty release], _firstProperty = nil;
[_thirdProperty release], _thirdProperty = nil;
// Assigned properties
secondProperty = nil;
[super dealloc];
}
This is repetitive and error-prone. Luckily, we may generate @synthesize instructions as well as destructors.
The alternative, is to use introspection to dynamically determine how the various properties need to be freed. For this, I suggest a category on NSObject:
@implementation NSObject (PropertyDealloc)
- (void)deallocProperties
{
Class class = [self class];
unsigned int pCount;
objc_property_t *properties = class_copyPropertyList(class, &pCount);
for (unsigned int i = 0; i < pCount; i++) {
objc_property_t property = properties[i];
NSString *propertyAttributes = [[[NSString alloc] initWithUTF8String:property_getAttributes(property)] autorelease];
NSArray *propertyAttributeArray = [propertyAttributes componentsSeparatedByString:@","];
BOOL isRetained = NO;
for (NSString *string in propertyAttributeArray) {
isRetained = isRetained || [string isEqual:@"&"] || [string isEqual:@"C"];
}
if (isRetained) {
NSString *variableName = nil;
NSString *lastProperty = (NSString*)[propertyAttributeArray lastObject];
if ([lastProperty hasPrefix:@"V"]) {
variableName = [lastProperty substringFromIndex:1];
}
if (variableName != nil) {
Ivar ivar = class_getInstanceVariable(class, [variableName UTF8String]);
id value = object_getIvar(self, ivar);
object_setIvar(self, ivar, nil);
[value release];
}
}
}
free(properties);
}
@end
Usage is extremely simple:
- (void)dealloc
{
[self deallocProperties];
[super dealloc];
}
This post was inspired by Vincent Gable.
- (void)dealloc
{
// Retained properties
[_firstProperty release], _firstProperty = nil;
[_thirdProperty release], _thirdProperty = nil;
// Assigned properties
secondProperty = nil;
[super dealloc];
}
This is repetitive and error-prone. Luckily, we may generate @synthesize instructions as well as destructors.
The alternative, is to use introspection to dynamically determine how the various properties need to be freed. For this, I suggest a category on NSObject:
@implementation NSObject (PropertyDealloc)
- (void)deallocProperties
{
Class class = [self class];
unsigned int pCount;
objc_property_t *properties = class_copyPropertyList(class, &pCount);
for (unsigned int i = 0; i < pCount; i++) {
objc_property_t property = properties[i];
NSString *propertyAttributes = [[[NSString alloc] initWithUTF8String:property_getAttributes(property)] autorelease];
NSArray *propertyAttributeArray = [propertyAttributes componentsSeparatedByString:@","];
BOOL isRetained = NO;
for (NSString *string in propertyAttributeArray) {
isRetained = isRetained || [string isEqual:@"&"] || [string isEqual:@"C"];
}
if (isRetained) {
NSString *variableName = nil;
NSString *lastProperty = (NSString*)[propertyAttributeArray lastObject];
if ([lastProperty hasPrefix:@"V"]) {
variableName = [lastProperty substringFromIndex:1];
}
if (variableName != nil) {
Ivar ivar = class_getInstanceVariable(class, [variableName UTF8String]);
id value = object_getIvar(self, ivar);
object_setIvar(self, ivar, nil);
[value release];
}
}
}
free(properties);
}
@end
Usage is extremely simple:
- (void)dealloc
{
[self deallocProperties];
[super dealloc];
}
This post was inspired by Vincent Gable.
Comments (3)