How is release handled for @synthesized retain properties?

Solution 1:

Q1:

No. @synthesize does not modify the -dealloc for you. You have to -release the name yourself.

Q2:

Yes it will leak. Same reason as Q1.

Q3:

No it won't double-release. Same reason as Q1.

Q4:

Yes it will leak. Same reason as Q1.

Q5:

No it won't double-release. Same reason as Q1.


You can check this yourself by overriding -retain and -release and -dealloc to report what is going on.

#import <Foundation/Foundation.h>

@interface X : NSObject {}
@end
@implementation X
-(oneway void)release {
        NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1);
        [super release];
}
-(id)retain {
        NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1);
        return [super retain];
}
-(void)dealloc {
        NSLog(@"Dealloc %p", self);
        [super dealloc];
}
@end

@interface Y : NSObject {
        X* x;
}
@property (nonatomic, retain) X* x;
@end
@implementation Y
@synthesize x;
- (void)dealloc { [x release]; [super dealloc]; }
@end

int main () {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
        Y* y = [[Y alloc] init];
        X* x = [[X alloc] init];
        y.x = x;
        [y release];
        [x release];
        [pool drain];                                                    
        return 0;
}

In Q1, Q2 and Q4, the last -retainCount of x is 1, so there is a leak, and in Q3 and Q5 the last -retainCount is 0 and -dealloc is called, so there is no leak.

Solution 2:

From the Objective-C documentation on properties:

dealloc

Declared properties fundamentally take the place of accessor method declarations; when you synthesize a property, the compiler only creates any absent accessor methods. There is no direct interaction with the dealloc method—properties are not automatically released for you. Declared properties do, however, provide a useful way to cross-check the implementation of your dealloc method: you can look for all the property declarations in your header file and make sure that object properties not marked assign are released, and those marked assign are not released.

This essentially answers all your questions.

Solution 3:

The simple and general rule: if you allocate, retain, or copy an object, YOU have to release it.

When you use the retain setter semantic setting in a @synthesize statement, you're asking the compiler to build for you a setter that calls retain on the object. Nothing more, nothing less. And since you are retaining that object (even though it's via magically auto-generated code), you have to release it, and where to release it is in -(void)dealloc.

Solution 4:

Something else it's worth knowing - if you have a synthesised property, setting that property to nil (using dot syntax, of course) will release the ivar for you.