AVAudioPlayer在预期时不释放内存

时间:2013-04-28 08:01:02

标签: loops delegates avaudioplayer

我正在写一个“叙述者”类型的应用程序,它按顺序读出段落中的每个句子。为实现这一目标,我有以下几点:

- (void) startSentPlayLoop {
    _isInPlayingLoop = YES;
    _currentlyPlayingSentNo=-1;
    [self audioPlayerDidFinishPlaying:nil successfully:NO];
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    if (_isInPlayingLoop) {
        _currentlyPlayingSentNo++;
        [LMAudioPlayer playAudioFileForSent:_currentlyPlayingSentNo withDelegateAs:self];
     }
}

并在文件LMAudioPlayer.m

+ (void) playAudioFileForSent:(int)sentNo withDelegateAs:(id<AVAudioPlayerDelegate>)delegate {
    AVAudioPlayer* audioInstance = [[AVAudioPlayer alloc] initWithContentsOfURL:[self urlFromSentNo] error:&error];
    audioInstance.delegate = delegate;
    [audioInstance play];
}

一切运转良好。我在仪器中注意到,在玩十个句子时,会创建十个AVAudioPlayer实例(每个句子都有一个新的),并且当所有句子都用完时,所有这些实例都会被释放(有点构建一个堆栈,并最终调用popAll()) )。我猜这是因为在audioPlayerDidFinishPlaying方法中,我调用了playAudioFileForSent,它创建了一个有点递归。

为了避免这种情况(我想要一个句子播放完成,释放内存然后开始下一个句子),我尝试将playAudioFileForSent方法调用移动到单独的循环,但没有改变。以下是我修改后的代码:

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    if (_isInPlayingLoop) {
        _currentlyPlayingSentNo++;
        [self performSelectorInBackground:@selector(playNextSentenceInLoop:) withObject:nil];
     }
}

- (void)playNextSentenceInLoop:(id)sender {
    [LMAudioPlayer playAudioFileForSent:_currentlyPlayingSentNo withDelegateAs:self];
}

所以,我猜想如果我让audioPlayerDidFinishPlaying方法返回,并在新线程中调用playAudioFileForSent,则可以避免递归堆栈的建立。这没有发生,我仍然得到相同的情况 - 堆栈建立,然后立即拆除所有。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

这一行:

AVAudioPlayer* audioInstance = [[AVAudioPlayer alloc] initWithContentsOfURL:[self urlFromSentNo] error:&error];

正在创建“AVAudioPlayer”的多个副本。

如果你想节省内存,你需要找到一种方法来重复使用你的“audioInstance”对象,而不是每次调用该方法时都创建一个新对象。

我的建议是将“audioInstance”设为属性或ivar(实例变量),然后如果它已经存在,请在完成上一个音频文件后将其重置为新URL的内容,然后重新启动播放。