我正在写一个“叙述者”类型的应用程序,它按顺序读出段落中的每个句子。为实现这一目标,我有以下几点:
- (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,则可以避免递归堆栈的建立。这没有发生,我仍然得到相同的情况 - 堆栈建立,然后立即拆除所有。我该如何解决这个问题?
答案 0 :(得分:0)
这一行:
AVAudioPlayer* audioInstance = [[AVAudioPlayer alloc] initWithContentsOfURL:[self urlFromSentNo] error:&error];
正在创建“AVAudioPlayer”的多个副本。
如果你想节省内存,你需要找到一种方法来重复使用你的“audioInstance
”对象,而不是每次调用该方法时都创建一个新对象。
我的建议是将“audioInstance
”设为属性或ivar(实例变量),然后如果它已经存在,请在完成上一个音频文件后将其重置为新URL的内容,然后重新启动播放。