iOS开发拓展篇—音频处理(音乐播放器3)

说明:这篇文章主要介绍音频工具类和播放工具类的封装。

一、控制器间数据传递

1.两个控制器之间数据的传递

第一种方法:self.parentViewController.music=self.music[indexPath.row];不能满足

第二种做法:把整个数组传递给它

第三种做法:设置一个数据源,设置播放控制器的数据源是这个控制器。self.parentViewController.dataSource=self;好处:没有耦合性,任何实现了协议的可以作为数据源。

第四种做法:把整个项目会使用到的音频资源交给一个工具类去管理,这样就不用传递过去了。直接向工具类索要资源就可以。

二、封装一个音频工具类

新建一个音频工具类,用来管理音乐数据(音乐模型)

iOS开发拓展篇—音频处理(音乐播放器3)

工具类中的代码设计如下:

YYMusicTool.h文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYMusicTool.h
 3 //
 4  5 #import <Foundation/Foundation.h>
 6 @class YYMusicModel;
 7 @interface YYMusicTool : NSObject
 8 /**
 9  * 返回所有的歌曲
10 */ 11 + (NSArray *)musics;
12 13 /**
14  * 返回正在播放的歌曲
15 */ 16 + (YYMusicModel *)playingMusic;
17 + (void)setPlayingMusic:(YYMusicModel *)playingMusic;
18 19 /**
20  * 下一首歌曲
21 */ 22 + (YYMusicModel *)nextMusic;
23 24 /**
25  * 上一首歌曲
26 */ 27 + (YYMusicModel *)previousMusic;
28 @end
iOS开发拓展篇—音频处理(音乐播放器3)

YYMusicTool.m文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYMusicTool.m
 3 //
 4  5 #import "YYMusicTool.h"  6 #import "YYMusicModel.h"  7 #import "MJExtension.h"  8  9 @implementation YYMusicTool
10 11 static NSArray *_musics;
12 static YYMusicModel *_playingMusic;
13 14 /**
15  * @return 返回所有的歌曲
16 */ 17 +(NSArray *)musics
18 {
19 if (_musics==nil) {
20 _musics=[YYMusicModel objectArrayWithFilename:@"Musics.plist"];
21  }
22 return _musics;
23 }
24 25 +(void)setPlayingMusic:(YYMusicModel *)playingMusic
26 {
27 /* 28  *如果没有传入需要播放的歌曲,或者是传入的歌曲名不在音乐库中,那么就直接返回
29 如果需要播放的歌曲就是当前正在播放的歌曲,那么直接返回
30 */ 31 if (!playingMusic || ![[self musics]containsObject:playingMusic]) return;
32 if (_playingMusic == playingMusic) return;
33 _playingMusic=playingMusic;
34 }
35 /**
36  * 返回正在播放的歌曲
37 */ 38 +(YYMusicModel *)playingMusic
39 {
40 return _playingMusic;
41 }
42 43 /**
44  * 下一首歌曲
45 */ 46 +(YYMusicModel *)nextMusic
47 {
48 //设定一个初值 49 int nextIndex = 0;
50 if (_playingMusic) {
51 //获取当前播放音乐的索引 52 int playingIndex = [[self musics] indexOfObject:_playingMusic];
53 //设置下一首音乐的索引 54 nextIndex = playingIndex+1;
55 //检查数组越界,如果下一首音乐是最后一首,那么重置为0 56 if (nextIndex>=[self musics].count) {
57 nextIndex=0;
58  }
59  }
60 return [self musics][nextIndex];
61 }
62 63 /**
64  * 上一首歌曲
65 */ 66 +(YYMusicModel *)previousMusic
67 {
68 //设定一个初值 69 int previousIndex = 0;
70 if (_playingMusic) {
71 //获取当前播放音乐的索引 72 int playingIndex = [[self musics] indexOfObject:_playingMusic];
73 //设置下一首音乐的索引 74 previousIndex = playingIndex-1;
75 //检查数组越界,如果下一首音乐是最后一首,那么重置为0 76 if (previousIndex<0) {
77 previousIndex=[self musics].count-1;
78  }
79  }
80 return [self musics][previousIndex];
81 }
82 @end
iOS开发拓展篇—音频处理(音乐播放器3)

三、封装一个音乐播放工具类

该工具类中的代码设计如下:

YYAudioTool.h文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYAudioTool.h
 3 //
 4  5 #import <Foundation/Foundation.h>
 6 #import <AVFoundation/AVFoundation.h>
 7 @interface YYAudioTool : NSObject
 8 /**
 9  *播放音乐文件
10 */ 11 +(BOOL)playMusic:(NSString *)filename;
12 /**
13  *暂停播放
14 */ 15 +(void)pauseMusic:(NSString *)filename;
16 /**
17  *播放音乐文件
18 */ 19 +(void)stopMusic:(NSString *)filename;
20 21 /**
22  *播放音效文件
23 */ 24 +(void)playSound:(NSString *)filename;
25 /**
26  *销毁音效
27 */ 28 +(void)disposeSound:(NSString *)filename;
29 @end
iOS开发拓展篇—音频处理(音乐播放器3)

YYAudioTool.m文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYAudioTool.m
 3 //
 4  5 #import "YYAudioTool.h"  6  7 @implementation YYAudioTool
 8 /**
 9  *存放所有的音乐播放器
 10 */  11 static NSMutableDictionary *_musicPlayers;
 12 +(NSMutableDictionary *)musicPlayers
 13 {
 14 if (_musicPlayers==nil) {
 15 _musicPlayers=[NSMutableDictionary dictionary];
 16  }
 17 return _musicPlayers;
 18 }
 19  20 /**
 21  *存放所有的音效ID
 22 */  23 static NSMutableDictionary *_soundIDs;
 24 +(NSMutableDictionary *)soundIDs
 25 {
 26 if (_soundIDs==nil) {
 27 _soundIDs=[NSMutableDictionary dictionary];
 28  }
 29 return _soundIDs;
 30 }
 31  32  33 /**
 34  *播放音乐
 35 */  36 +(BOOL)playMusic:(NSString *)filename
 37 {
 38 if (!filename) return NO;//如果没有传入文件名,那么直接返回
 39 //1.取出对应的播放器  40 AVAudioPlayer *player=[self musicPlayers][filename];
 41  42 //2.如果播放器没有创建,那么就进行初始化  43 if (!player) {
 44 //2.1音频文件的URL  45 NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
 46 if (!url) return NO;//如果url为空,那么直接返回
 47  48 //2.2创建播放器  49 player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
 50  51 //2.3缓冲  52 if (![player prepareToPlay]) return NO;//如果缓冲失败,那么就直接返回
 53  54 //2.4存入字典  55 [self musicPlayers][filename]=player;
 56  }
 57  58 //3.播放  59 if (![player isPlaying]) {
 60 //如果当前没处于播放状态,那么就播放  61 return [player play];
 62  }
 63  64 return YES;//正在播放,那么就返回YES  65 }
 66  67 +(void)pauseMusic:(NSString *)filename
 68 {
 69 if (!filename) return;//如果没有传入文件名,那么就直接返回
 70  71 //1.取出对应的播放器  72 AVAudioPlayer *player=[self musicPlayers][filename];
 73  74 //2.暂停  75 [player pause];//如果palyer为空,那相当于[nil pause],因此这里可以不用做处理  76  77 }
 78  79 +(void)stopMusic:(NSString *)filename
 80 {
 81 if (!filename) return;//如果没有传入文件名,那么就直接返回
 82  83 //1.取出对应的播放器  84 AVAudioPlayer *player=[self musicPlayers][filename];
 85  86 //2.停止  87  [player stop];
 88  89 //3.将播放器从字典中移除  90  [[self musicPlayers] removeObjectForKey:filename];
 91 }
 92  93 //播放音效  94 +(void)playSound:(NSString *)filename
 95 {
 96 if (!filename) return;
 97 //1.取出对应的音效  98 SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
 99 100 //2.播放音效
101 //2.1如果音效ID不存在,那么就创建 102 if (!soundID) {
103 104 //音效文件的URL 105 NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
106 if (!url) return;//如果URL不存在,那么就直接返回 107 108 OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
109 NSLog(@"%ld",status);
110 //存入到字典中 111 [self soundIDs][filename]=@(soundID);
112  }
113 114 //2.2有音效ID后,播放音效 115  AudioServicesPlaySystemSound(soundID);
116 }
117 118 //销毁音效 119 +(void)disposeSound:(NSString *)filename
120 {
121 //如果传入的文件名为空,那么就直接返回 122 if (!filename) return;
123 124 //1.取出对应的音效 125 SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
126 127 //2.销毁 128 if (soundID) {
129  AudioServicesDisposeSystemSoundID(soundID);
130 131 //2.1销毁后,从字典中移除 132  [[self soundIDs]removeObjectForKey:filename];
133  }
134 }
135 @end
iOS开发拓展篇—音频处理(音乐播放器3)

四、在音乐播放控制器中的代码处理

YYPlayingViewController.m文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYPlayingViewController.m
 3 //
 4  5 #import "YYPlayingViewController.h"  6 #import "YYMusicTool.h"  7 #import "YYMusicModel.h"  8 #import "YYAudioTool.h"  9  10 @interface YYPlayingViewController ()
 11 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
 12 @property (weak, nonatomic) IBOutlet UILabel *songLabel;
 13 @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
 14 @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
 15 @property(nonatomic,strong)YYMusicModel *playingMusic;
 16 - (IBAction)exit;
 17  18 @end  19  20 @implementation YYPlayingViewController
 21 #pragma mark-公共方法
 22 -(void)show
 23 {
 24 //1.禁用整个app的点击事件  25 UIWindow *window=[UIApplication sharedApplication].keyWindow;
 26 window.userInteractionEnabled=NO;
 27  28 //2.添加播放界面
 29 //设置View的大小为覆盖整个窗口  30 self.view.frame=window.bounds;
 31 //设置view显示  32 self.view.hidden=NO;
 33 //把View添加到窗口上  34  [window addSubview:self.view];
 35  36 //3.检测是否换了歌曲  37 if (self.playingMusic!=[YYMusicTool playingMusic]) {
 38  [self RresetPlayingMusic];
 39  }
 40  41 //4.使用动画让View显示  42 self.view.y=self.view.height;
 43 [UIView animateWithDuration:0.25 animations:^{
 44 self.view.y=0;
 45 } completion:^(BOOL finished) {
 46  47 //设置音乐数据  48  [self starPlayingMusic];
 49 window.userInteractionEnabled=YES;
 50  }];
 51 }
 52 #pragma mark-私有方法
 53 //重置正在播放的音乐  54 -(void)RresetPlayingMusic
 55 {
 56 //1.重置界面数据  57 self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"];
 58 self.songLabel.text=nil;
 59 self.singerLabel.text=nil;
 60  61 //2.停止播放  62  [YYAudioTool stopMusic:self.playingMusic.filename];
 63 }
 64 //开始播放音乐数据  65 -(void)starPlayingMusic
 66 {
 67 //1.设置界面数据
 68  69 //取出当前正在播放的音乐
 70 // YYMusicModel *playingMusic=[YYMusicTool playingMusic];
 71  72 //如果当前播放的音乐就是传入的音乐,那么就直接返回  73 if (self.playingMusic==[YYMusicTool playingMusic]) return;
 74 //存取音乐  75 self.playingMusic=[YYMusicTool playingMusic];
 76 self.iconView.image=[UIImage imageNamed:self.playingMusic.icon];
 77 self.songLabel.text=self.playingMusic.name;
 78 self.singerLabel.text=self.playingMusic.singer;
 79  80 //2.开始播放  81  [YYAudioTool playMusic:self.playingMusic.filename];
 82  83 }
 84  85 #pragma mark-内部的按钮监听方法
 86 //返回按钮  87 - (IBAction)exit {
 88 //1.禁用整个app的点击事件  89 UIWindow *window=[UIApplication sharedApplication].keyWindow;
 90 window.userInteractionEnabled=NO;
 91  92 //2.动画隐藏View  93 [UIView animateWithDuration:0.25 animations:^{
 94 self.view.y=window.height;
 95 } completion:^(BOOL finished) {
 96 window.userInteractionEnabled=YES;
 97 //设置view隐藏能够节省一些性能  98 self.view.hidden=YES;
 99  }];
100 }
101 @end
iOS开发拓展篇—音频处理(音乐播放器3)

注意:先让用户看到界面上的所有东西后,再开始播放歌曲。

提示:一般的播放器需要做一个重置的操作。

  当从一首歌切换到另外一首时,应该先把上一首的信息删除,因此在show动画显示之前,应该检测是否换了歌曲,如果换了歌曲,则应该做一次重置操作。

实现效果(能够顺利的切换和播放歌曲,下面是界面显示):

iOS开发拓展篇—音频处理(音乐播放器3)iOS开发拓展篇—音频处理(音乐播放器3)iOS开发拓展篇—音频处理(音乐播放器3)

五、补充代码

YYMusicsViewController.m文件

iOS开发拓展篇—音频处理(音乐播放器3)
 1 //  2 // YYMusicsViewController.m
 3 //
 4  5 #import "YYMusicsViewController.h"  6 #import "YYMusicModel.h"  7 #import "MJExtension.h"  8 #import "YYMusicCell.h"  9 #import "YYPlayingViewController.h" 10 #import "YYMusicTool.h" 11 12 @interface YYMusicsViewController ()
13 14 @property(nonatomic,strong)YYPlayingViewController *playingViewController;
15 @end 16 17 @implementation YYMusicsViewController
18 #pragma mark-懒加载
19 20 -(YYPlayingViewController *)playingViewController
21 {
22 if (_playingViewController==nil) {
23 _playingViewController=[[YYPlayingViewController alloc]init];
24  }
25 return _playingViewController;
26 }
27 28 - (void)viewDidLoad
29 {
30  [super viewDidLoad];
31 }
32 33 #pragma mark - Table view data source
34 /**
35  *一共多少组
36 */ 37 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
38 {
39 return 1;
40 }
41 /**
42  *每组多少行
43 */ 44 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
45 {
46 return [YYMusicTool musics].count;
47 }
48 /**
49  *每组每行的cell
50 */ 51 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
52 {
53 YYMusicCell *cell=[YYMusicCell cellWithTableView:tableView];
54 cell.music=[YYMusicTool musics][indexPath.row];
55 return cell;
56 }
57 /**
58  * 设置每个cell的高度
59 */ 60 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
61 {
62 return 70;
63 }
64 65 /**
66  * cell的点击事件
67 */ 68 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
69 {
70 //1.取消选中被点击的这行 71  [tableView deselectRowAtIndexPath:indexPath animated:YES];
72 73 //2.设置正在播放的歌曲 74  [YYMusicTool setPlayingMusic:[YYMusicTool musics][indexPath.row]];
75 76 //调用公共方法 77  [self.playingViewController show];
78 79 // //执行segue跳转
80 // [self performSegueWithIdentifier:@"music2playing" sender:nil]; 81 }
82 @end
iOS开发拓展篇—音频处理(音乐播放器3)
上一篇:《Ext JS高级程序设计》节选: 一个结合DataWrite和RowEditor的Grid示例


下一篇:iOS开发拓展篇—xib中关于拖拽手势的潜在错误