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
复制代码
目录
相关文章
|
2月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
106 3
|
2月前
|
API 开发工具 Android开发
iOS 和 Android 平台的开发有哪些主要区别?
iOS与Android开发区别:iOS用Objective-C/Swift,App Store唯一下载渠道;Android用Java/Kotlin,多商店发布(如Google Play、华为市场)。设计上,iOS简洁一致,Android灵活可定制。开发工具,iOS用Xcode,Android用Android Studio。硬件和系统多样性,iOS统一,Android复杂。权限管理、审核流程及API各有特点,开发者需依据目标平台特性进行选择。
36 3
|
11天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
11天前
|
存储 Swift iOS开发
使用Swift开发一个简单的iOS应用的详细步骤。
使用Swift开发iOS应用的步骤包括:创建Xcode项目,设计界面(Storyboard或代码),定义数据模型,实现业务逻辑,连接界面和逻辑,处理数据存储(如Core Data),添加网络请求(必要时),调试与测试,根据测试结果优化改进,最后提交至App Store或其它平台发布。
31 0
|
11天前
|
安全 Swift iOS开发
【Swift 开发专栏】Swift 与 UIKit:构建 iOS 应用界面
【4月更文挑战第30天】本文探讨了Swift和UIKit在构建iOS应用界面的关键技术和实践方法。Swift的简洁语法、类型安全和高效编程模型,加上与UIKit的紧密集成,使开发者能便捷地创建用户界面。UIKit提供视图、控制器、布局、动画和事件处理等功能,支持灵活的界面设计。实践中,遵循设计原则,合理组织视图层次,运用布局和动画,以及实现响应式设计,能提升界面质量和用户体验。文章通过登录、列表和详情界面的实际案例展示了Swift与UIKit的结合应用。
|
11天前
|
存储 安全 Swift
【Swift 开发专栏】使用 Swift 开发一个简单的 iOS 应用
【4月更文挑战第30天】本文介绍了使用 Swift 开发简单 iOS 待办事项应用的步骤。首先,阐述了 iOS 开发的吸引力及 Swift 语言的优势。接着,详细说明了应用的需求和设计,包括添加、查看和删除待办事项的功能。开发步骤包括创建项目、界面搭建、数据存储、功能实现,并提供了相关代码示例。最后,强调了实际开发中需注意的细节和优化,旨在帮助初学者掌握 Swift 和 iOS 开发基础。
|
19天前
|
iOS开发 开发者 UED
利用SwiftUI构建动态列表:iOS开发的新范式
【4月更文挑战第22天】在本文中,我们将深入探讨如何使用SwiftUI来创建动态列表。SwiftUI是苹果最新推出的用户界面工具集,它允许开发者以声明式的方式描述用户界面,从而简化了代码的复杂性。我们将通过具体的代码实例,展示如何利用SwiftUI的List和ForEach视图来创建动态列表,并讨论其在实际开发中的应用。
18 2
|
23天前
|
API 定位技术 iOS开发
IOS开发基础知识:什么是 Cocoa Touch?它在 iOS 开发中的作用是什么?
【4月更文挑战第18天】**Cocoa Touch** 是iOS和Mac OS X应用的核心框架,包含面向对象库、运行时系统和触摸优化工具。它提供Mac验证的开发模式,强调触控接口和性能,涵盖3D图形、音频、网络及设备访问API,如相机和GPS。是构建高效iOS应用的基础,对开发者至关重要。
21 0
|
1月前
|
搜索推荐 iOS开发 开发者
利用SwiftUI构建动态用户界面:iOS开发新篇章
【4月更文挑战第10天】在移动应用的世界中,流畅的用户体验和引人注目的界面设计是至关重要的。随着SwiftUI的推出,iOS开发者被赋予了创造高度动态且响应式界面的能力。本文将深入探讨如何利用SwiftUI的强大特性来实现一个动态用户界面,包括其声明性语法、状态绑定以及视图更新机制。我们将通过一个天气应用案例,了解如何有效地运用这些工具来提升应用的交互性和视觉吸引力。
|
1月前
|
开发工具 Swift iOS开发
利用SwiftUI构建动态用户界面:iOS开发新范式
【4月更文挑战第3天】 随着苹果不断推进其软件开发工具的边界,SwiftUI作为一种新兴的编程框架,已经逐渐成为iOS开发者的新宠。不同于传统的UIKit,SwiftUI通过声明式语法和强大的功能组合,为创建动态且响应式的用户界面提供了一种更加简洁高效的方式。本文将深入探讨如何利用SwiftUI技术构建具有高度自定义能力和响应性的用户界面,并展示其在现代iOS应用开发中的优势和潜力。