【问题标题】:Best ways to play simple sound effect in iOS在 iOS 中播放简单音效的最佳方法
【发布时间】:2012-04-05 04:43:32
【问题描述】:

我发现了一些关于在 iOS 中播放声音的相互矛盾的数据。每次用户触摸屏幕时播放简单的“ping”声音片段的推荐方法是什么?

【问题讨论】:

    标签: iphone objective-c ios


    【解决方案1】:

    我用这个:

    头文件:

    #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。

    【讨论】:

    • 这很棒。我正在使用 SystemSoundID 的 C 数组,但我刚刚达到了一个点,那就是太多 schlepp 无法处理。基于此切换到某些东西。谢谢!
    • 这不适用于 ARC。要将它与 ARC 一起使用,您必须添加一个完成回调函数,您可以在其中处理 systemsound。如果您在 dealloc 中执行此操作,声音会立即被杀死:AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 像这样的示例
    • @Maverick1st 这与 ARC 完美配合,您只需确保您的 SoundEffect 对象不会立即被释放,例如将其分配给属性。
    【解决方案2】:

    这是在 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);
    

    【讨论】:

    • 要完成此操作,请添加此 AudioServicesAddSystemSoundCompletion 以播放完成通知,并添加此 AudioServicesRemoveSystemSoundCompletion 以取消注册通知。
    • 此代码无法在 ARC 中编译。我添加了“__bridge”来修复:AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &audioEffect);
    【解决方案3】:

    (对正确答案的小修改,以处理音频)

    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);
    });
    

    【讨论】:

    • 这是异步播放声音的最佳方式。
    【解决方案4】:

    您可以使用AVFoundationAudioToolbox

    这里有两个分别使用库的例子。

    【讨论】:

      【解决方案5】:

      这是 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)
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-13
        • 2011-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-17
        • 1970-01-01
        • 2021-03-14
        相关资源
        最近更新 更多