12

我想通过AVAudioPlayer播放MP3,我认为这很简单。不幸的是,它不是很有效。下面是我所做的:AVAudioPlayer立即停止播放ARC

  • 为了测试的缘故,我创建了一个新的iOS应用程序(单 视图)在Xcode。
  • 我加入了AVFoundation框架到项目还有#import <AVFoundation/AVFoundation.h>ViewController.m

  • 我增加了一个MP3文件到Apps的文档“文件夹。

  • 我改变了ViewControllersviewDidLoad:以下几点:

代码:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   

    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  

    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 

    [audioPlayer play]; 

    //[NSThread sleepForTimeInterval:20]; 
} 

不幸的是,音频明显停止它开始播放之后。如果我取消对sleepForTimeInterval的评论,它会播放20秒,然后停止播放。只有使用ARC进行编译时才会出现此问题,否则,它会完美地工作。

+0

你不需要启动另一个线程来播放音频。你有没有试过提供一个错误指针来查看是否有任何东西被记录? – isaac

+0

你会得到什么错误? – Daniel

+0

是的,我通过一个NSError initWithContensOfURL。它保持零,但...所以我没有得到任何错误,它只是立即停止播放。 – Phlibbo

回答

7

的问题是,与ARC编译时,您需要确保通过插入release呼叫保持到要永葆因为编译器会自动修复“不平衡” alloc实例的引用(至少在概念上,阅读Mikes Ash blog post for more details )。您可以通过将实例分配给属性或实例变量来解决此问题。

在Phlibbo情况下,代码将被改造成:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   
    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 
    [audioPlayer play]; 
    [audioPlayer release]; // inserted by ARC 
} 

而且AVAudioPlayer它会立即停止播放当没有提及离开它被释放。

我自己并没有使用ARC,只是简单地阅读了一下。如果您对此有更多了解,请对我的回答发表评论,我会用更多信息对其进行更新。

更多ARC信息:
Transitioning to ARC Release Notes
LLVM Automatic Reference Counting

+0

你是绝对正确的。如上述评论所述。 ;) – yinkou

+0

我不使用ARC,我尝试使用与编写相同的方式播放短音。我只听到第一个声音(并且感谢第一次播放声音时AVAudioPlayer的错误)。所以最好你的代码会削减音频的第一秒,最坏的情况是它会在声音自行停止前停止播放。 – Gargo

+0

@Gargo:正如Mattias在他的文章中写道的那样,这段代码解释了为什么玩家没有在我的案件中工作,这是故意的。如果您没有经验,您应该查看AVAudioPlayer教程。 – Phlibbo

3

使用AVAudioPlayer在头文件伊娃与strong

@property (strong,nonatomic) AVAudioPlayer *audioPlayer 
3

如果需要多个AVAudioPlayers在同一时间播放,创建一个NSMutableDictionary。将该键设置为文件名。从字典通过委托回调,像这样删除:

-(void)playSound:(NSString*)soundNum { 


    NSString* path = [[NSBundle mainBundle] 
         pathForResource:soundNum ofType:@"m4a"]; 
    NSURL* url = [NSURL fileURLWithPath:path]; 

    NSError *error = nil; 
    AVAudioPlayer *audioPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; 

    audioPlayer.delegate = self; 

    if (_dictPlayers == nil) 
     _dictPlayers = [NSMutableDictionary dictionary]; 
    [_dictPlayers setObject:audioPlayer forKey:[[audioPlayer.url path] lastPathComponent]]; 
    [audioPlayer play]; 

} 

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {   
    [_dictPlayers removeObjectForKey:[[player.url path] lastPathComponent]]; 
} 
+0

这是同时播放声音的最佳解决方案。如果您使用AVAudioPlayer作为属性,则会在播放下一个声音时发布对象,而某些用户正在使用AudioServicesPlaySystemSound,但苹果拒绝应用程序,因为它在设备静音时仍会播放,并且无法检查设备是否为静音。 – Zeeshan