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
复制代码
目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
6天前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
89 66
|
17天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
21天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
23天前
|
存储 前端开发 Swift
探索iOS开发:从新手到专家的旅程
本文将带您领略iOS开发的奇妙之旅,从基础概念的理解到高级技巧的掌握,逐步深入iOS的世界。文章不仅分享技术知识,还鼓励读者在编程之路上保持好奇心和创新精神,实现个人成长与技术突破。
|
26天前
|
安全 IDE Swift
探索iOS开发之旅:从初学者到专家
在这篇文章中,我们将一起踏上iOS开发的旅程,从基础概念的理解到深入掌握核心技术。无论你是编程新手还是希望提升技能的开发者,这里都有你需要的指南和启示。我们将通过实际案例和代码示例,展示如何构建一个功能齐全的iOS应用。准备好了吗?让我们一起开始吧!
|
1月前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
30 2
|
iOS开发
IOS下P2P播放器开发如何实现?
IOS下P2P播放器开发如何实现?1)播放器在播放磁力链、或者torrrent文件时,调用自身的P2P引擎,p2p引擎里面通过torrent或者磁力链信息,去通过tracker、DHT寻找周围的peer邻居,然后获取数据。
2193 0
|
1月前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
50 9
|
1月前
|
vr&ar Android开发 iOS开发
安卓与iOS开发中的用户界面设计原则
【10月更文挑战第41天】探索移动应用开发的精髓,本文将深入分析安卓和iOS平台上用户界面设计的核心原则。通过比较两大操作系统的设计哲学,我们将揭示如何打造直观、易用且美观的应用程序界面。无论你是初学者还是资深开发者,这篇文章都将为你提供宝贵的见解和实用的技巧,帮助你在竞争激烈的应用市场中脱颖而出。