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

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

一、控制器间数据传递

1.两个控制器之间数据的传递
第一种方法:self.parentViewController.music=self.music[indexPath.row];不能满足
第二种做法:把整个数组传递给它
第三种做法:设置一个数据源,设置播放控制器的数据源是这个控制器。self.parentViewController.dataSource=self;好处:没有耦合性,任何实现了协议的可以作为数据源。
第四种做法:把整个项目会使用到的音频资源交给一个工具类去管理,这样就不用传递过去了。直接向工具类索要资源就可以。

二、封装一个音频工具类
新建一个音频工具类,用来管理音乐数据(音乐模型)
  
工具类中的代码设计如下:
YYMusicTool.h文件
复制代码
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
复制代码
YYMusicTool.m文件

复制代码
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
复制代码

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

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

YYAudioTool.h文件

复制代码
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
复制代码
YYAudioTool.m文件

复制代码
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
复制代码

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

YYPlayingViewController.m文件

复制代码
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
复制代码
注意:先让用户看到界面上的所有东西后,再开始播放歌曲。

提示:一般的播放器需要做一个重置的操作。
  当从一首歌切换到另外一首时,应该先把上一首的信息删除,因此在show动画显示之前,应该检测是否换了歌曲,如果换了歌曲,则应该做一次重置操作。
实现效果(能够顺利的切换和播放歌曲,下面是界面显示):

五、补充代码

YYMusicsViewController.m文件

复制代码
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
复制代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容