0
votes

With an 'Analyze', in the dealloc I get: Incorrect decrement of the reference count of an object that is not owned at this point by the caller

#import <AVFoundation/AVFoundation.h>
@interface XYZViewController : UIViewController
@property (retain) AVAudioRecorder  *recorder;
@end
@implementation XYZViewController
@synthesize recorder;
- (void) dealloc
{
    [self.recorder release];
    [super dealloc];
}
- (void) viewDidLoad
{
    NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];
    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithFloat: 44100.0],                 AVSampleRateKey,
                          [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
                          [NSNumber numberWithInt: 1],                         AVNumberOfChannelsKey,
                          [NSNumber numberWithInt: AVAudioQualityMax],         AVEncoderAudioQualityKey,
                          nil];
    NSError *error;
    self.recorder = [[[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error] autorelease];
}
@end

Does it mean I shouldn't release it? Also, I tried to 'Profile' the code and I get a memory leak from [[[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error] autorelease] no matter what.

2

2 Answers

4
votes

You should release the ivar directly, rather than going through the accessor:

- (void)dealloc
{
    [recorder release];
    [super dealloc];
}

You don't own the returned object of an accessor, so you shouldn't release it.

1
votes

Rather than sending -release to the object returned by the property accessor method, set the property itself to nil:

- (void)dealloc {
    self.recorder = nil;
    [super dealloc];
}

The compiler will know to do the right thing because you've specified the storage semantics in the property declaration. Synthesizing a property declared with retain semantics is effectively equivalent to writing the following accessor methods:

- (AVAudioRecorder *)recorder {
    return recorder;
}

- (void)setRecorder:(AVAudioRecorder *)newRecorder {
    [newRecorder retain];
    [recorder release];
    recorder = newRecorder;
}

When you write self.recorder = nil, the compiler translates it into [self setRecorder:nil]. Setting a property to nil in this way therefore avoids both memory leaks and dangling pointers, involves less boilerplate on your part, and more clearly expresses the intent of the code.

Finally, it never hurts to re-read The Objective-C Programming Language, which has a section on declared properties; and Advanced Memory Management Programming Guide, which goes over all the different approaches to memory management in detail.