引用计数的减少不正确&内存泄漏

时间:2011-12-14 16:27:16

标签: objective-c release avfoundation memory-leaks avaudiorecorder

通过'分析',在dealloc中得到: 调用者此时不拥有的对象的引用计数的不正确减少

#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

这是否意味着我不应该发布它? 此外,我试图'配置'代码,无论如何我都会从[[[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error] autorelease]收到内存泄漏。

2 个答案:

答案 0 :(得分:4)

您应该直接释放ivar,而不是通过访问者:

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

您不拥有访问者的返回对象,因此您不应该将其释放。

答案 1 :(得分:1)

不是将-release发送到属性访问器方法返回的对象,而是将属性本身设置为nil

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

编译器将知道做正确的事情,因为您已在属性声明中指定了存储语义。合成用retain语义声明的属性实际上等同于编写以下访问器方法:

- (AVAudioRecorder *)recorder {
    return recorder;
}

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

编写self.recorder = nil时,编译器会将其转换为[self setRecorder:nil]。因此,以这种方式将属性设置为nil可以避免内存泄漏和悬空指针,您可以使用更少的样板,并且更清楚地表达代码的意图。

最后,重新阅读The Objective-C Programming Language永远不会受到伤害,Advanced Memory Management Programming Guide有一个关于声明属性的部分;和{{3}},它详细介绍了所有不同的内存管理方法。