音效工具类的封装

分析

  • 音效工具类的职责与便利性
    • 能够记录音效文件的SoundID,无需每一次播报音效的时候都需要重新获取
    • 能够对存放在系统中的SoundID进行缓存优化处理
  • 与单例类的比较
    • 单利类的话,一旦我们第一次初始化之后,将不会被释放,对于缓存的优化处理不友好
    • 类方法(静态方法),无需初始化对象,每一个类在编译的时候编译系统都会开辟对于的内存,性能要稍微优于单利类
  • 类方法的特点
    • 不能在类方法中调用self.获取对应的属性
    • 类方法中既不能用属性也不用成员变量,但是可以用全局静态变量

代码

  • SPPSoundPlayManager.h文件
#import <Foundation/Foundation.h>

@interface SPPSoundPlayManager : NSObject

/**
 播放音效

 @param name 声音文件名(带后缀)
 @param alert 是否振动
 */
+ (void)playSoundWithName:(NSString *)name alert:(BOOL)alert;

//清除缓存
+ (void)clearMemory;

@end
  • SPPSoundPlayManager.m文件
#import "SPPSoundPlayManager.h"
#import <AVFoundation/AVFoundation.h>

//全局的静态变量(static修饰符:静态变量,只能分配一次内存,即只能初始化一次,只会开辟一次内存空间,不会反复重新加载内存)
//音效缓存字典(key: 文件名name, value: soundID)
static NSMutableDictionary *cacheDict;

@interface SPPSoundPlayManager()

//静态方法中是无法访问属性的,改用C的静态变量
//@property(nonatomic, strong) NSMutableDictionary *cacheDict;

@end

@implementation SPPSoundPlayManager

//第一次加载当前类(类被加载到内存中)的时候会先执行load方法(1. 只会执行一次 2. 一旦你创建了这一个文件就会在编译时调用,与你是否使用它无关)
+ (void)load {
    NSLog(@"load");
}

//第一次使用当前类的时候会执行(1. 只会执行一次 2. 你使用了这个类就会执行,不使用则不执行)
+ (void)initialize {
    NSLog(@"initialize");   //类的生命周期

    //初始化缓存字典
    cacheDict = [NSMutableDictionary dictionary];
}

/**
 播放系统音效

 @param name 音效的文件名(带后缀)
 @param alert 是否振动
 */
+ (void)playSoundWithName:(NSString *)name alert:(BOOL)alert {

    /**
     1. 以name为Key, SoundID为Value
     2. 先判断缓存字典对一个的Value是否有值 --> soundID == 0 就代表没有值/没有缓存
     3. 没有值就创建, 有的话直接播放
     */

    //1. 创建系统音效soundID
    SystemSoundID soundid = [cacheDict[name] unsignedIntValue];

    //2. 先检查该文件是否在当前缓存文件中(为0代表没有在缓存中,那就去创建)
    if (soundid == 0) {
        //1. 创建音效类
        //1.1 获取包中音效文件的url路径
        NSURL *url = [[NSBundle mainBundle] URLForResource:name withExtension:nil];

        //1.2 音效的播放是由系统底层来播放(基于C的接口)
        ///传入音频路径url就会和soundID进行绑定,之后需要播放的时候, 只需要调用soundID, 就能找到对应的URL地址
        ///这样做的好处就是soundID对音效有一个缓存,当音效文件第一次加载时,系统会将音效文件随机分配一个soundID,可以在下次播放时直接使用soundID播放,而无需再次获取对应的url地址
        AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundid);

        //1.3 将文件名与soundid加入到缓存字典中
        [cacheDict setValue:@(soundid) forKey:name];
    }

    //3. 播放音效(音效: 不超过30s的短音乐)
    ///播放音效有两种类型,一种是带振动(必须要真机),一种不带振动
    if (alert) {
        //带振动
        AudioServicesPlayAlertSound(soundid);

    }else {
        //不带振动
        AudioServicesPlaySystemSound(soundid);
    }
}

+ (void)clearMemory {
    //1. 静态变量字典在ARC下面释放内存不能直接设置为nil,应该先清除内部对象
    [cacheDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        //2. 清除静态字典内部的缓存
        ///ARC只对OC对象有效,对C对象无效(这就是为什么C对象至今仍保留了retain和release方法)
        //2.1 获取缓存的soundID
        SystemSoundID soundID = [obj unsignedIntValue];
        //2.2 C对象要释放一般使用CFRelease(),注意是释放C对象(堆里),而soundID是UInt32类型(栈里),所以看出有一些特殊的系统类内部会给出单独的API用于释放,此时应优先使用系统给出的单独的API,而不能一味套用CFRelease()
        //Dispose: 处理int类型的栈内存不能直接使用release
        AudioServicesDisposeSystemSoundID(soundID);

    }];
    //3. 移除字典所有元素
    [cacheDict removeAllObjects];
}

@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值