Swift - AVAudioPlayer, sound doesn't play correctly

萝らか妹 提交于 2019-11-27 07:17:26

问题


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.


回答1:


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!



来源:https://stackoverflow.com/questions/27911968/swift-avaudioplayer-sound-doesnt-play-correctly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!