1

My background music plays once the view controller has loaded. which is great, however every time the user returns to that screen it plays again. and layers itself into a incoherent mess. I need the music to play once and continue to play until the user turns it off in the settings.

As I understand from the code i've written. Once the view loads in creates the audioPlayer it then checks to see if the boolean isPlaying is set to false. If it is then it executes the playMusic function. if its set to true it should do nothing. I am confused on why it plays the music again on top of the previous iteration.

Could it be creating the audio player every time the view is loaded? if so how would i go about fixing that?

Once the app is loaded the user is presented with a start screen. the music starts playing there.

They then press either start, purchase hints, or settings. in order to go back to the previous screen you hit a back button. which the way the design of the app is setup, always takes you back to the start screen. the segues are just set up in that. i control dragged to the next view controller and chose the show option.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var audioPlayer = AVAudioPlayer()

    @IBOutlet weak var  musicToggle: UIButton!

    var isPlaying = false

    @IBAction func musicTogglebtn(_ sender: Any) {

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            audioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "weiss", ofType: "mp3")!))
            audioPlayer.prepareToPlay()
        } catch {
            print(error)
        }

        if isPlaying == false {
            playMusic()
        } else {
            return
        }
    }

    func playMusic() {
        audioPlayer.play()
        isPlaying = true
    }


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

}
Bista
  • 7,869
  • 3
  • 27
  • 55
Chris Levely
  • 131
  • 1
  • 10

3 Answers3

2

The key piece of information you don't provide is how does the user get to and from this screen?

If you present/push another view controller on top of it and the user dismisses/pops that view controller, your view controller with the audio player will be revealed, with it's state still intact.

If you pop/dismiss your ViewController and then present a new one, or keep pushing/presenting a new copy on top of the previous one then each view controller will have it's own state, and its own audio player so you'll get more and more sounds playing on top of each other.

My guess is that is your problem.

Post information about how the user navigates your view controllers and we can help you sort it out.

EDIT:

Based on your replies, I understand your problem now.

The sound playing issue is a symptom of a bigger problem. You have set up your back button to trigger a show segue. That creates an additional, brand-new copy of your view controller which gets added to the top of the navigation stack. That is wrong, and will lead to lots and lots of problems.

You should set up your navigation controller to show a navigation bar. When you do that, it will set up a back button for you, and that back button will pop the front view controller off the stack and expose the one underneath. That is the expected behavior of a back button.

If instead you want your back button to take you all the way to the start screen then you should remove the segue link from the back button and instead connect it to an IBAction that sends the message popToRootViewController to the navigation controller.

This is going to lead to your next problem, which is when you click the sound back button, you're going to close the current view controller and lose access to your audio player.

You should probably move your sound playing control to a central sound manager object. This would be a good use for a singleton. (Look that up.) Add methods to your sound manager singleton that let you start and stop sounds, and invoke the sound play method when you display your view controller, and stop the sound from playing when you want it to stop.

Community
  • 1
  • 1
Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • I've updated the question to tell how the user navigates from page to page – Chris Levely Dec 22 '16 at 14:05
  • See the edit to my answer. Your current navigation logic is all wrong. – Duncan C Dec 22 '16 at 15:22
  • Thank you!, See, I never knew the difference between the segues, as far as I knew, they were a preference more than anything. – Chris Levely Dec 22 '16 at 15:25
  • 1
    Segues always create and display a new copy of the view controller they transition to, with the exception of unwind segues. (Embed segues are a special case too, since they link to a child view controller that's embedded in the current view controller.) – Duncan C Dec 22 '16 at 19:30
  • So what's the difference between "show" and present modally? Or really I guess what does each adaptive segue mean? And why was "show" the wrong option – Chris Levely Dec 22 '16 at 19:34
  • 1
    Show pushes a new view controller onto a navigation stack. Present modally presents a modal view controller on top of the current view controller, but not as part of a navigation stack. – Duncan C Dec 22 '16 at 19:36
  • Ok, so from your answer. Once the view loads it played the music, and is added to the navigation stack, but is never removed from it so when I go back it just creates another one, thus the layering effect. Is that right? – Chris Levely Dec 22 '16 at 19:44
  • Quick update :) thanks again Duncan, My app is now functioning perfectly and the music doesn't layer. And I also learned a thing or two about the navigation stack and segues – Chris Levely Dec 23 '16 at 07:07
1

View Did Load every time calling means, it's important to consider how you are presenting your screen. Example, say you are doing this in ViewController A, and you moved to View Controller B. Now, how you are coming from View Controller B to A is important. If you are again presenting View Controller A on top of that means, View Did Load again loads. Or else if you are popping or dismissing view controller and coming to View Controller A means, it won't load.

Sivajee Battina
  • 4,124
  • 2
  • 22
  • 45
0

When you navigate to ViewController isPlaying will always be false you need to make sure isPlaying is globally accessible or maybe use the dispatch_once GCD refer to this doc Dispatch once in Swift 3

Or you can even try to have a shared class with the isPlaying as a property but this is not entirely clean.

Community
  • 1
  • 1
GyroCocoa
  • 1,542
  • 16
  • 19