Swift - AVAudioPlayer,声音不能正确播放 [英] Swift - AVAudioPlayer, sound doesn't play correctly

查看:31
本文介绍了Swift - AVAudioPlayer,声音不能正确播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这是我目前所拥有的:

//...类 AppDelegate: UIResponder, UIApplicationDelegate {变量窗口:UIWindow?func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) ->布尔{//在应用程序启动后覆盖自定义点.//通知权限让类型: UIUserNotificationType = UIUserNotificationType.Sound |UIUserNotificationType.Alert让设置: UIUserNotificationSettings = UIUserNotificationSettings(forTypes:类型,类别:nil)application.registerUserNotificationSettings(settings)返回真}func 应用程序(应用程序:UIApplication!,didReceiveLocalNotification 通知:UILocalNotification!){让状态: UIApplicationState = application.applicationStatevar audioPlayer = AVAudioPlayer()如果(状态== UIApplicationState.Active){//创建声音变量错误:NSError?var audioPlayer = AVAudioPlayer()AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)AVAudioSession.sharedInstance().setActive(true, error: nil)让 soundURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sound", ofType: "wav")!)audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: &error)如果(错误!= nil){println("出现错误:\(error)")} 别的 {audioPlayer.prepareToPlay()音频播放器.play()}//创建警报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()它只播放不到一秒钟.就像它突然被释放一样(?).

我尝试了以下两件事:

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

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

在此先感谢所有可以帮助我理解/解决此问题的人.

解决方案

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

我希望我说得够清楚了,如果没有,请随时问更多!

Because UILocalNotification is not being displayed while the application is in active stat, I'm trying to configure an UIAlertController and playing a little sound when it appears.

I've no problem, in the AppDelegate, to handle the notification/create the alert. My problem concerns the sound. Indeed, it doesn't play correctly.

Here is what I have so far :

//...
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)

    }

}

With that, when the player go through this line : audioPlayer.play() It only play for less then a second. Like if it was suddently deallocated maybe (?).

I tried the two things below :

  1. Switching back the AVAudioPlayer status to inactive: AVAudioSession.sharedInstance().setActive(false, error: nil) just before the alert creation (or just after showing it). If I do that, the sound is played correctly. But, this method is a synchronous (blocking) operation, so it delays other thing (alert being shown after the sound). Apparently not a good solution.
  2. Move the audioPlayer property (var audioPlayer = AVAudioPlayer()) to the class level, just under the window (var window: UIWindow?). If I do that, the sound is played correctly and the alert is shown correctly too.

I don't understand why it works like that. Am I missing something? Is it the proper way to solve my problem?

Thanks in advance to everyone who could help me understand/fixing this.

解决方案

You already provided the correct solution to your problem and that would be #2; to have a class-level audioPlayer property. Why is this so? Well, that's because in the code you setup the player, start the playback, show the pop-up and after everything is done, the method exits its scope. The automated memory management (ARC) works so that any local variables get released when you exit the scope of that variable. If you consider that sound playback is asynchronous (eg. it will play without blocking the main thread), you exit the scope before the audio player is finished playing the sound. ARC notices that audioPlayer is a local variable and releases it at that point, but the sound is not done playing yet.

I hope I was clear enough, if not feel free to ask more!

这篇关于Swift - AVAudioPlayer,声音不能正确播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆