Swift - AVAudioPlayer,声音播放不正确

Posted

技术标签:

【中文标题】Swift - AVAudioPlayer,声音播放不正确【英文标题】:Swift - AVAudioPlayer, sound doesn't play correctly 【发布时间】:2015-01-12 22:39:27 【问题描述】:

因为UILocalNotification 在应用程序处于活动状态时没有显示,我正在尝试配置一个UIAlertController 并在它出现时播放一点声音。

我没有问题,在AppDelegate,处理通知/创建警报。我的问题与声音有关。确实,它播放不正确。

这是我目前所拥有的:

//...
class AppDelegate: UIResponder, UIApplicationDelegate 

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
    // Override point for customization after application launch.

    // Notifications permissions
    let types: UIUserNotificationType = UIUserNotificationType.Sound | UIUserNotificationType.Alert
    let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
    application.registerUserNotificationSettings(settings)

    return true


func application(application: UIApplication!, didReceiveLocalNotification notification: UILocalNotification!) 
    let state : UIApplicationState = application.applicationState
    var audioPlayer = AVAudioPlayer()

    if (state == UIApplicationState.Active) 
        // Create sound

        var error:NSError?
        var audioPlayer = AVAudioPlayer()

        AVAudiosession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
        AVAudioSession.sharedInstance().setActive(true, error: nil)

        let soundURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sound", ofType: "wav")!)

        audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: &error)

        if (error != nil) 
            println("There was an error: \(error)")
         else 
            audioPlayer.prepareToPlay()
            audioPlayer.play()
        

        // Create alert
        let alertController = UIAlertController(title: "Alert title", message: "Alert message.", preferredStyle: .Alert)

        let noAction = UIAlertAction(title: "No", style: .Cancel)  (action) in
            // ...
        
        let yesAction = UIAlertAction(title: "Yes", style: .Default)  (action) in
            // ...
        

        alertController.addAction(noAction)
        alertController.addAction(yesAction)

        self.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

    


这样,当玩家通过这条线时:audioPlayer.play() 它只播放不到一秒钟。就像它突然被释放一样(?)。

我尝试了以下两件事:

    AVAudioPlayer 状态切换回非活动状态:AVAudioSession.sharedInstance().setActive(false, error: nil) 在警报创建之前(或在显示之后)。如果我这样做,声音就会正确播放。但是,这种方法是同步(阻塞)操作,所以它会延迟其他事情(在声音之后显示警报)。显然不是一个好的解决方案。 将 audioPlayer 属性 (var audioPlayer = AVAudioPlayer()) 移动到类级别,就在窗口 (var window: UIWindow?) 下方。如果我这样做,声音就会正确播放,并且警报也会正确显示。

我不明白为什么会这样。我错过了什么吗?这是解决我的问题的正确方法吗?

提前感谢所有可以帮助我理解/解决此问题的人。

【问题讨论】:

【参考方案1】:

您已经为您的问题提供了正确的解决方案,那就是#2;拥有一个类级别的audioPlayer 属性。为什么会这样? 好吧,那是因为在代码中你设置了播放器,开始播放,显示弹出窗口,一切都完成后,方法退出了它的范围。自动内存管理 (ARC) 可以在您退出该变量的范围时释放任何局部变量。如果您认为声音播放是异步的(例如,它将在不阻塞主线程的情况下播放),则在音频播放器完成播放声音之前退出范围。 ARC 注意到 audioPlayer 是一个局部变量并在此时释放它,但声音还没有播放完毕。

我希望我已经足够清楚了,如果不能再问更多!

【讨论】:

我怀疑这个对象在它结束播放声音之前就被释放了。但是,在解决方案 #2 中,将属性放置在此级别(尤其是在 AppDelegate 中)不是不好的做法吗?没有合适的方法解决问题吗? @lchamp 有实例变量不是坏习惯,坏的是有全局变量。但我确实同意在应用程序委托中使用它并不理想。我会做什么(特别是如果你不止一次演奏这个声音);创建一个单例类(例如 SoundPlayer),然后您可以从任何地方调用它。在该类中添加一个包含实际AVAudioPlayer 的实例变量。然后可能有一个类似SoundPlayer.sharedPlayer.play(SoundType.Alert) 或类似的接口。 我按照建议创建了一个单例。谢谢! @lchamp 你能发布对你有用的代码吗?我也有同样的问题。 SoundPlayer.swift : pastebin.com/eX4iv3S4 。像这样使用:SoundPlayer.sharedInstance.playSound()。目前它只使用一种声音(因为这是我想要的),但你可以很容易地为 playSound 方法添加一个参数。

以上是关于Swift - AVAudioPlayer,声音播放不正确的主要内容,如果未能解决你的问题,请参考以下文章

在其他 swift 文件中调用时,AVAudioPlayer 不会播放声音

Swift AVAudioPlayer 不播放声音

swift AVAudioPlayer播放音频时声音太小

AVAudioPlayer Swift 3不播放声音[重复]

Swift 3 多个 AVAudioPlayer

AVAudioPlayer 不播放音频文件 - swift