AV 框架(Audio 和 Video 框架)里的 AVAudioPlayer 类能播放 iOS 支持的所有音频格式。AVAudioPlayer 实例的 delegate 属性允许我们通过事件获得通知,例如当音频播放被打断或者播放音频文件出错时。我们来看个例子,演示如何播放我们程序 bundle 中的音频文件:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
dispatch_queue_t dispatchQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(dispatchQueue, ^(void)
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"MySong"ofType:@"mp3"];//获取音频文件
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSError *error = nil;
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:fileDataerror:&error];
if (self.audioPlayer != nil)
{
self.audioPlayer.delegate = self;
if ([self.audioPlayer prepareToPlay] &&[self.audioPlayer play])
{
//成功播放音乐
} else {
//播放失败
}
} else {
/*
无法实例AVAudioPlayer
*/}
});
}
可以看到文件中的数据首先被加载到一个 NSData 实例,然后被传递到 AVAudioPlayer类的 initWithData:error:方法。因为我们需要 MP3 文件的绝对路径来获取文件数据,我们调用 NSBundle 类的 mainBundle 方法来从程序的配置中获取信息。然后像代码中写的那样,用 NSBundle 类的 pathForResource:ofType:方法来得到指定类型资源的绝对路径。
在 viewDidLoad 方法中,我们用 GCD 来异步从歌曲数据中加载数据到 NSData 实例中,而且把数据提供给音频播放器。这么做是因为加载不同长度的音频文件中的数据需要很长时间,如果我们在主线程中做的话会有影响 UI 体验的风险。因此,我们利用一个全局的并发队列来确保代码不在主线程中运行
因为我们将 AVAudioPlayer 实例赋值给了 audioPlayer,属性,我们需要指定该属性如何定义:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface Playing_Audio_FilesViewController:UIViewController <AVAudioPlayerDelegate>
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
可以看到,我们把视图控制器作为了音频播放器的 delegate 。这样就可以每当播放歌曲被打断或结束时从系统中得到消息。掌握了这些信息后,我们就可以在程序中做出正确操作,例如开始播放另一个音频文件时