Reputation: 6087
I have got two ViewControllers. One is "ViewController", the second is "SecondViewController".
On the ViewController, I have var player = AVAudioPlayer()
. I have loaded and played BGM there successfully, and then I pushed the SecondViewController into view.
On the SecondViewController, I used this code to stop the audio player on the ViewController:
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController") as? ViewController
viewController?.player.pause()
But I get error Thread 1: EXC_BAD_ACCESS (code=1, address=0x38)
From what I learned from browsing around, this happened because I tried to access the player while the player hasn't been initialized yet.
But how it can be? Hasn't it been initialized already? The music is still playing up to when this error occurs. What's wrong and how to fix it so that I can manipulate audio player from a different ViewController than the currently active one (but it's already active in background)? Thanks.
Upvotes: 0
Views: 369
Reputation: 21144
You are instantiating a new view controller; not using the same view controller that presented SecondViewController and so AudioPlayer that gets created is not same as the previous AudioPlayer. You should somehow refer to the presenting view controller.
One way to do would be by what is called a delegate pattern,
class ViewController: UIViewController {
...
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SecondViewController" {
if let secondViewController = segue.destinationViewController as? SecondViewController {
secondViewController.delegate = self
}
}
}
// MARK: SecondViewControllerDelegate
func stopPlayer() {
player.stopPlayer()
}
}
protocol SecondViewControllerDelegate {
func stopPlayer()
}
class SecondViewController: UIViewController {
...
var delegate: SecondViewControllerDelegate?
func stopPlayer() {
delegate?.stopPlayer()
}
}
Or, then, you can also pass AVPlayer from first view controller to SecondViewController and use it to stop from SecondViewController itself,
class ViewController: UIViewController {
...
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SecondViewController" {
if let secondViewController = segue.destinationViewController as? SecondViewController {
secondViewController.player = self.player
}
}
}
}
class SecondViewController: UIViewController {
...
var player: AVPlayer!
func stop() {
player.stop()
}
}
Upvotes: 2
Reputation: 7764
The problem is that instantiateViewControllerWithIdentifier
creates a new ViewController. It doesn't return the one that you've been on. Anyway, trying to access something on a previous view controller doesn't seem like a good design to me.
One option is to pass AVAudioPlayer
to your second VC in prepareForSegue
method. You can declare an AVAudioPlayer
property and set it there.
Upvotes: 0
Reputation: 4677
instantiateViewControllerWithIdentifier creates a new instance of your view controller.
Instead put a property on secondViewController of type YourViewController and set that in the prepareForSegue in YourViewController.
Upvotes: 1