1

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

- (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];
}

它一切运作良好。我在 Instruments 中注意到,在播放十个句子时,会创建十个 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,可能会避免递归堆栈的堆积。这没有发生,我仍然遇到同样的情况 - 堆栈建立起来,然后一次全部拆除。我该如何解决这个问题?

4

1 回答 1

0

这一行在这里:

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

是什么创建了“AVAudioPlayer”的多个副本。

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

我的建议是使“ audioInstance”成为属性或 ivar(实例变量),然后如果它已经存在,则在您之前的音频文件完成后将其重置为新 URL 的内容,然后重新开始播放。

于 2013-04-28T08:09:16.397 回答