委托函数 audioPlayerDidFinishPlaying 每次都不会触发

Posted

技术标签:

【中文标题】委托函数 audioPlayerDidFinishPlaying 每次都不会触发【英文标题】:Delegate function audioPlayerDidFinishPlaying is not fired each time 【发布时间】:2012-11-19 22:00:06 【问题描述】:

我有类似应用程序的键盘,并且我正在将每个新的 AVAudioPlayer 添加到 NSMutableArray 以便我可以叠加声音。 我的问题是,那个 delagate 函数

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag

如果在短时间间隔内有击键,则不会触发。例如,如果我以 0.5 秒或更长时间的间隔进行中风,一切正常。知道为什么吗? 当他的声音播放完成时,我想释放内存并从数组中删除对象。

更新

.h

@interface .. <AVAudioPlayerDelegate>

    NSMutableArray *soundObjects;


@property (nonatomic,strong) AVAudioPlayer *audioPlayer;

.m

-(void)playSound 

    //
    //  play sound
    //

    _audioPlayer = [self loadWav:_soundID];
    _audioPlayer.delegate = self;

    [soundObjects addObject:_audioPlayer];
    AVAudioPlayer *temp = [soundObjects objectAtIndex:soundIndex];
    soundIndex = [soundObjects count];
    [temp play];


-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag

#ifdef DEBUG_SOUND
        NSLog(@"FLAG");
        soundIndex--;
        [soundObjects removeObjectAtIndex:soundIndex];
#endif


- (AVAudioPlayer *)loadWav:(NSString *)filename 
    NSURL * url = [[NSBundle mainBundle] URLForResource:filename withExtension:@"mp3"];
    NSError * error;

    AVAudioPlayer * player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];

    if (!player) 
#ifdef DEBUG_MODE
        NSLog(@"Error loading %@: %@", url, error.localizedDescription);
#endif
     else 
        [player prepareToPlay];
    
    return player;

【问题讨论】:

【参考方案1】:

开发人员文档中有几个 NSQueue 示例作为一个快速示例,我将使用我自己的作品整理的 Obj C 食谱书中的改编。

//This method detatches the instruction from the main thread
-(void)keyStrokeSelector:(NSString*)objectSound


       [NSThread detachNewThreadSelector:@selector(keyStroke:objectSound)
                                toTarget:self
                              withObject:nil];


 

//this selector will acctually execute the task
-(void)keyStroke:(NSString *)objectSound

   @autoreleasepool 
      //code to play the sound
   

我希望这会有所帮助。关于上述代码的一些注意事项:您必须为每个单独的线程使用自动释放池,否则引用计数(MRC 或 ARC)将不起作用,因为它只能在自动释放池中工作,发生在主线程之外的线程中的代码应该被编码像其他任何东西一样,它只会执行并运行到完成。如果您在子线程中有无限循环,则在测试您的应用程序时可能不明显,但是如果我正确记住了后台线程的当前最大时间,操作系统将在十分钟后终止应用程序。更重要的是,如果您不创建特定于线程的@autoreleasepool,那么即使您没有在新线程中创建新对象,当它们被传入时,您的对象也不会被释放并且会占用内存占用空间。它们将获得保留计数并保留在内存中。

我希望这会有所帮助,祝你的程序好运

【讨论】:

【参考方案2】:

尝试在后台进程中触发播放。这是我第一次讨论这个问题,在不知道更多细节的情况下,我只能推测你是如何演奏这些声音的。如果您在主线程上播放声音,那么也在主线程上的键盘将无响应,而声音正在被缓冲并被触发以在同一线程上播放。在处理媒体时,您通常应该加载它并从主线程播放它,以消除竞争条件的可能性。如果加载图像、歌曲或电影,则通常不应在主线程上,因为 UI 将无响应。

【讨论】:

@那个家伙我刚刚更新了我的问题。我是线程新手,但也许我的更新会告诉你更多......谢谢。 您的代码看起来不错,从我简要介绍的内容来看。我建议更清楚的是从主线程或队列中实际播放音乐。有几种方法可以做到这一点,对于大多数熟悉面向对象编程但并不熟悉并发和多任务处理的人来说,第一种也是最简单的方法是使用 NSQueue 系列对象来创建“脱离主线程”任务。我认为积木更容易,但前提是您对积木感到满意。 GCD 支持积木,当他们第一次开始使用它时,大多数人似乎会感到畏惧。 @那个家伙 嗯,我不聪明。如何在我的项目中使用 NSQueue?能不能给我展示一些使用示例?

以上是关于委托函数 audioPlayerDidFinishPlaying 每次都不会触发的主要内容,如果未能解决你的问题,请参考以下文章

如何用 func 委托替换 Action 委托,将值返回给函数

浅谈C#委托和事件(转载)

没有返回类型的函数委托

使用 IAsyncResult 委托函数

如何从自定义函数中调用委托函数?

C# 再次理解委托事件与函数作为参数