以下情况下的内存泄漏问题

时间:2011-04-29 05:25:57

标签: iphone memory-leaks avaudioplayer

点击播放按钮后,我收到内存泄漏....

我正在使用“运行和性能工具”下的“泄漏”工具进行测试....在模拟器上

第一次点击播放按钮时,我发现了泄漏.....

这是我的代码......

-(IBAction)play
{


    [self setPlayer];
    [self playme];  
}



-(IBAction)stop
{
    [self stopme];
    [self releasePlayer];

}


-(void)setPlayer
{

    NSURL *file = [[NSURL alloc] initFileURLWithPath:
                   [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"shut up.mp3"]];
    NSError *err = nil;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:&err];

    [file release];
    player.numberOfLoops = -1;
    [player prepareToPlay];
    player.volume=1.0;


}


-(void)playme
{
    if (!isPlaying)
    {
        [player play];
        isPlaying=YES;
    }
}


-(void)stopme
{
    if (isPlaying)
    {
        [player stop];
        isPlaying=NO;
    }
}

-(void)releasePlayer
{
    if(!isPlaying)
    {
        [player release];
        player=nil;
    }
    isPlaying=NO;
}

2 个答案:

答案 0 :(得分:2)

我认为,以下声明是内存泄漏的来源,

player = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:&err];

以下是讨论同一问题的SO帖子。

AVAudioPlayer memory leak

AVAudioPlayer memory leak

AVAudioPlayer Memory Leak - Media Player Framework

这是博客文章

AVAudioPlayer Memory Leak

<强>编辑:

根据博客教程,您的代码必须如下所示。

-(void)setPlayer
{

    NSURL *file = [[NSURL alloc] initFileURLWithPath:
                   [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"shut up.mp3"]];
    NSError *err = nil;

    NSData *data = [NSData dataWithContentsOfFile:file];
    AVAudioPlayer *player = [AVAudioPlayer alloc];    
    if([player initWithData:audioData error:NULL])
     {

        player.numberOfLoops = -1;
        [player prepareToPlay];
        player.volume=1.0;
        [player autorelease];
    } 
    else 
    {
        [player release];
        player = nil;
    }
    [file release];
}

无泄漏版本存储alloc返回的指针,而不是initWithData返回的指针:error:。这样,无论发生什么,玩家仍然可以被释放。

答案 1 :(得分:1)

Jhaliya的回答中的博客文章描述了一种泄漏,这种泄漏特定于当你的播放器无法启动音频时的情况,例如当它找不到文件时。

您的代码存在的真正问题是,只有在用户明确停止播放音频时才会释放播放器。如果音频播放到最后,您有一个keepCount为1的播放器实例。然后,如果用户再次播放,则创建一个新播放器并将其分配给player变量,泄漏旧变量。

最简单的解决方案是使player成为保留属性:

@property(nonatomic,retain)AVAudioPlayer *player;

然后,不是直接分配到ivar,而是使用mutator来设置播放器,如果有的话,它将隐式释放先前设置的实例:

[self setPlayer:[[[AVAudioPlayer alloc] initWithContentsOfURL:file error:&err] autorelease];

不要忘记在你的dealloc中发布它:

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