保留属性时的内存泄漏问题

5
我可以帮您翻译成中文。以下是需要翻译的内容:

我想在我的应用程序中的每个按钮点击时播放点击声音。为此,我创建了一个实用程序类,其.h和.m如下所示:

.h文件

@interface SoundPlayUtil : NSObject<AVAudioPlayerDelegate,AVAudioSessionDelegate>
{
    AVAudioPlayer *audioplayer;   
}
@property (retain, nonatomic) AVAudioPlayer *audioplayer;
-(id)initWithDefaultClickSoundName;
-(void)playIfSoundisEnabled;
@end

.m文件

@implementation SoundPlayUtil
@synthesize audioplayer;

-(id)initWithDefaultClickSoundName
{
self = [super init];
    if (self)
{
    NSString* BS_path_blue=[[NSBundle mainBundle]pathForResource:@"click"   ofType:@"mp3"];
    self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue]  error:NULL];
   [self.audioplayer prepareToPlay];
}
return self;
}

-(void)playIfSoundisEnabled
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:soundStatus]==YES)
{
    [self.audioplayer play];
}
}

-(void)dealloc
{
[audioplayer release];
[super dealloc];
}
@end

在任何类上点击按钮时,我正在执行以下操作

 SoundPlayUtil *obj = [[SoundPlayUtil alloc] initWithDefaultClickSoundName];
 [obj playIfSoundisEnabled];
 [obj release];

一切正常,我成功地播放了声音。但是当我分析代码时出现了问题。编译器显示在实用类的 .m 文件中的 initWithDefaultClickSoundName 方法存在内存泄漏,因为我发送了 alloc 方法到 self.audioplayer 但没有释放它。

什么是最好的释放该对象的位置?

2个回答

2

问题在于当你分配了这个对象后,它的保留计数将为1,然后你将该对象分配给一个保留属性对象。接着它将再次保留该对象,因此保留计数将变为2。

一个保留属性的setter代码大致如下:

- (void)setAudioplayer: (id)newValue
{
    if (audioplayer != newValue)
    {
        [audioplayer release];
        audioplayer = newValue;
        [audioplayer retain];
    }
}

更改:

self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue]  error:NULL];

喜欢;

self.audioplayer =[[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue]  error:NULL] autorelease];

或者像这样:
 AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue]  error:NULL];
 self.audioplayer = player;
 [player release];

感谢您的快速回答,我正在尝试避免自动释放,因此如果我实现您提供的第二个选项。在这种情况下,由于我已经保留了self.audioplayer并且audioplayer对象的保留计数为1。现在我将其分配给新对象player,其保留计数也为1。在将新值分配给self.audioplayer后,是否会出现我失去保留计数为1的对象的引用的情况? - abdus.me
之后我会释放临时对象,这样就不会创建任何孤儿或导致泄漏。 - Midhun MP
为什么要避免使用autorelease?一个sound对象的生命周期很可能比通过运行循环只经过一次的时间长,而使用autorelease与播放声音的成本相比微不足道。需要注意的是,在分配时保留计数可能是1,也可能不是1。绝对保留计数是没有意义的。 - bbum

0
self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue]  error:NULL];

在这里,您创建一个新对象,然后将其分配给一个保留的属性。但是,除了该属性之外,您再也没有对该对象的引用,因此它会泄漏。您已经增加了两次保留计数。
为了解决问题,按照以下优先顺序进行操作:
  1. 转换为ARC ;)
  2. 创建一个本地变量,将其分配给属性,然后释放它。

    Object *object = [[Object alloc] init];
    self.property = object;
    [object release];
    
  3. 在添加对象时添加autorelease调用:self.property = [[[Object alloc] init] autorelease];


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接