2
votes

I've created four ViewControllers in xcode that each play a different audio mix when a play button is pressed. If I navigate to another viewcontroller and press that play button...How do I stop all other audio from playing, and ensure that the new audio mix plays successfully?

The same code detailed below is present in the four ViewControllers. The only difference is I've created three new instances of musicPlayer. They are musicPlayerSummer,musicPlayerWinter,musicPlayerAutumn. And I've created new buttons for each viewcontroller.

Any suggestions would be appreciated.

Thank you

import UIKit import AVFoundation

class ViewControllerSpring: UIViewController {

var musicPlayer: AVAudioPlayer!
var mySongs = ["1", "2", "3", "4"]



override func viewDidLoad() {
    super.viewDidLoad()


    initAudio()


    // Do any additional setup after loading the view.

}

func initAudio() {



    let path = NSBundle.mainBundle().pathForResource(mySongs[0], ofType: "mp3")!

    do {

        musicPlayer = try AVAudioPlayer(contentsOfURL: NSURL(string: path)!)
        musicPlayer.prepareToPlay()
        musicPlayer.numberOfLoops = -1



    } catch let err as NSError {
       print(err.debugDescription)


    }




    let session:AVAudioSession = AVAudioSession.sharedInstance()

    do {
        try session.setCategory(AVAudioSessionCategoryPlayback)
    } catch {
        //catching the error.
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/

override func prefersStatusBarHidden() -> Bool {
    return true
}






@IBAction func springPlayPressed(sender: UIButton) {

    if musicPlayer.playing {

        musicPlayer.stop()


        // for normal state
        sender.setImage(UIImage(named: "play.png"), forState: UIControlState.Normal)


    } else {

        musicPlayer.play()





        // for Highlighted state
        sender.setImage(UIImage(named: "Pause.png"), forState: UIControlState.Normal)
    }
}

}

2
There are couple of ways. One way is delegation and other way is PostNotification. If there is only one player then should use delegation and if more player to stop then should use Notification Observer.Muzahid
Agreed, best practice go with above. But if you want to take a short cut... (generally considered bad practice)... make your players globals, or better than that make them each a singleton.MikeG
Why is it bad practice to make the players global?hoboman

2 Answers

2
votes

To solve this problem declare audioPlayer in appDelegate

// inside AppDelegate
var audioPlayer : AVAudioPlayer? = nil

then simply declare in your viewController :

var audioPlayer : AVAudioPlayer? {
    get {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        return appDelegate.audioPlayer
    }
    set {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.audioPlayer = newValue
    }
}
0
votes

You can use Notification.

Send a notification when audio finish:

[[NSNotificationCenter defaultCenter] postNotificationName:@"MyAudioTerminatedNotification" object:self];

Receive it to your other View:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioTerminatedNotification:) name:@"MyAudioTerminatedNotification" object:nil];

Do you action:

- (void)audioTerminatedNotification:(NSNotification *)notification {
   // Do you action
}

And dispose of it:

[[NSNotificationCenter defaultCenter] removeObserver:self];