【发布时间】:2012-04-05 04:43:32
【问题描述】:
我发现了一些关于在 iOS 中播放声音的相互矛盾的数据。每次用户触摸屏幕时播放简单的“ping”声音片段的推荐方法是什么?
【问题讨论】:
标签: iphone objective-c ios
我发现了一些关于在 iOS 中播放声音的相互矛盾的数据。每次用户触摸屏幕时播放简单的“ping”声音片段的推荐方法是什么?
【问题讨论】:
标签: iphone objective-c ios
我用这个:
头文件:
#import <AudioToolbox/AudioServices.h>
@interface SoundEffect : NSObject
{
SystemSoundID soundID;
}
- (id)initWithSoundNamed:(NSString *)filename;
- (void)play;
@end
源文件:
#import "SoundEffect.h"
@implementation SoundEffect
- (id)initWithSoundNamed:(NSString *)filename
{
if ((self = [super init]))
{
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
if (fileURL != nil)
{
SystemSoundID theSoundID;
OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &theSoundID);
if (error == kAudioServicesNoError)
soundID = theSoundID;
}
}
return self;
}
- (void)dealloc
{
AudioServicesDisposeSystemSoundID(soundID);
}
- (void)play
{
AudioServicesPlaySystemSound(soundID);
}
@end
您需要创建一个 SoundEffect 实例并直接调用它的方法 play。
【讨论】:
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 像这样的示例
SoundEffect 对象不会立即被释放,例如将其分配给属性。
这是在 iOS 中播放简单声音的最佳方式(不超过 30 秒):
//Retrieve audio file
NSString *path = [[NSBundle mainBundle] pathForResource:@"soundeffect" ofType:@"m4a"];
NSURL *pathURL = [NSURL fileURLWithPath : path];
SystemSoundID audioEffect;
AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
// call the following function when the sound is no longer used
// (must be done AFTER the sound is done playing)
AudioServicesDisposeSystemSoundID(audioEffect);
【讨论】:
(对正确答案的小修改,以处理音频)
NSString *path = [[NSBundle mainBundle] pathForResource:@"soundeffect" ofType:@"m4a"];
NSURL *pathURL = [NSURL fileURLWithPath : path];
SystemSoundID audioEffect;
AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
// Using GCD, we can use a block to dispose of the audio effect without using a NSTimer or something else to figure out when it'll be finished playing.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
AudioServicesDisposeSystemSoundID(audioEffect);
});
【讨论】:
【讨论】:
这是 Swift (4) 的更新答案:
import AudioToolbox
func playSound() {
var soundId: SystemSoundID = 0
guard let soundPath = Bundle.main.url(forResource: "Success7", withExtension: "wav") else {
print("Error finding file")
return
}
let error = AudioServicesCreateSystemSoundID(soundPath as CFURL, &soundId)
if error != kAudioServicesNoError {
print("Error loading sound")
return
}
AudioServicesPlaySystemSoundWithCompletion(soundId) {
AudioServicesDisposeSystemSoundID(soundId)
}
}
如果您想在一个视图中多次播放声音效果,那么您可以更聪明地加载和处理音频:
class YourViewController: UIViewController {
fileprivate lazy var soundId: SystemSoundID? = {
guard let soundPath = Bundle.main.url(forResource: "Success7", withExtension: "wav") else {
return nil
}
var soundId: SystemSoundID = 0
let error = AudioServicesCreateSystemSoundID(soundPath as CFURL, &soundId)
if error != kAudioServicesNoError {
return nil
}
return soundId
}()
func playScannedSound() {
guard let soundId = self.soundId else {
return
}
AudioServicesPlaySystemSoundWithCompletion(soundId, nil)
}
deinit {
guard let soundId = self.soundId else {
return
}
AudioServicesDisposeSystemSoundID(soundId)
}
}
【讨论】: