skip to Main Content

I’m creating a jigsaw puzzle app for kids with 24 different little puzzles in 24 different scenes. I’ve put the background music in a Singleton, like so:

class MusicHelper { static let sharedHelper = MusicHelper() var audioPlayerBGM: AVAudioPlayer?
    func playBackgroundMusic() {
        let BGM = URL(fileURLWithPath: Bundle.main.path(forResource: "jigsawBGM", ofType: "wav")!)
        do {
            audioPlayerBGM = try AVAudioPlayer(contentsOf:BGM as URL)
            audioPlayerBGM!.numberOfLoops = -1
            audioPlayerBGM!.prepareToPlay()
            audioPlayerBGM!.play()
            audioPlayerBGM!.volume = 0.1
        } catch {
            print("Cannot play the file")
        }
    }
    
    func pauseBackgroundMusic() {
        let BGM = URL(fileURLWithPath: Bundle.main.path(forResource: "jigsawBGM", ofType: "wav")!)
        do {
            audioPlayerBGM = try AVAudioPlayer(contentsOf:BGM as URL)
            audioPlayerBGM!.pause()
        } catch {
            print("Cannot play the file")
        }
    }
}

For the sake of parents’ sanity, I’ve also written a snippet of code to mute the BGM. Like so:

@IBOutlet weak var muteMusicButton: UIButton!
@IBAction func muteMusic(_ sender: UIButton) {
    sender.isSelected = !sender.isSelected
 
    if muteMusicButton.isSelected {
        MusicHelper.sharedHelper.pauseBackgroundMusic()
    } else {
        MusicHelper.sharedHelper.playBackgroundMusic()
    }
}

I’ve put the muteMusicButton in a separate view controller scene (like a ‘controls’ or ‘settings’ window for the app user). It’s a custom button with different images for default state (‘music on’ image) and selected state (‘music off’ image).
The problem is that the button resets to default state when its view controller is dismissed, so that when you access the view controller again music is still paused, but the button displays the ‘music on’ image, and you have to press it twice to start the music again.

Is there a way to make to make a button ‘remember’ its selected state when you dismiss/re-access its view controller?
(UserDefault perhaps, which I am notoriously incompetent at!)

Or should I go about the whole thing in a completely different manner?

3

Answers


  1. Sounds like would be best to read the isPlaying property at viewWillAppear of the ViewController to update the button state accordingly.

    https://developer.apple.com/documentation/avfaudio/avaudioplayer/1390139-isplaying

    func viewWillAppear() {
       muteMusicButton.selected = !MusicHelper.sharedHelper.audioPlayerBGM.isPlaying
    }
    
    Login or Signup to reply.
  2. Instead of saying "I’m rubbish at UserDefault" take a little time to learn about it.

    Very briefly, though…

    Decide on a "key" for your setting — let’s use "isMuted"

    When you’re going to start playing music, read the value of that key from UserDefaults:

    let b: Bool = UserDefaults.standard.bool(forKey: "isMuted")
    if b {
        // don't play the music
    } else {
        // play the music
    }
    

    When you show your "settings" view controller (in viewDidLoad for example), read that value and set the button’s isSelected property:

    let b: Bool = UserDefaults.standard.bool(forKey: "isMuted")
    muteMusicButton.isSelected = b
    

    When the user taps the button, write the new value to UserDefaults (based on your code):

    @IBAction func muteMusic(_ sender: UIButton) {
        
        sender.isSelected = !sender.isSelected
    
        UserDefaults.standard.set(sender.isSelected, forKey: "isMuted")
        
        if muteMusicButton.isSelected {
    
            MusicHelper.sharedHelper.pauseBackgroundMusic()
        }
    
        else {
    
            MusicHelper.sharedHelper.playBackgroundMusic()
        }
    }
    
    Login or Signup to reply.
  3. Try this:

    class MusicHelper {
        static let sharedHelper = MusicHelper()
        var audioPlayerBGM: AVAudioPlayer?
    
        init() {
            let BGM = URL(fileURLWithPath: Bundle.main.path(forResource: "jigsawBGM", ofType: "wav")!)
            audioPlayerBGM = try? AVAudioPlayer(contentsOf: BGM)
            audioPlayerBGM?.numberOfLoops = -1
            audioPlayerBGM?.volume = 0.1
            audioPlayerBGM?.prepareToPlay()
    
             let isMuted = UserDefaults.standard.bool(forKey: "isMuted")
             if !isMuted {
                 audioPlayerBGM?.play()
             }
        }
    
        func playBackgroundMusic() {
            audioPlayerBGM?.play()
        }
    
        func pauseBackgroundMusic() {
            audioPlayerBGM?.pause()
        }
    }
    
    @IBOutlet weak var muteMusicButton: UIButton!
    
    
    @IBAction func muteMusic(_ sender: UIButton) {
    
        sender.isSelected = UserDefaults.standard.bool(forKey: "isMuted")
     
        if muteMusicButton.isSelected {
            MusicHelper.sharedHelper.pauseBackgroundMusic()
            UserDefaults.standard.set(false, forKey: "isMuted")
         } else {
            MusicHelper.sharedHelper.playBackgroundMusic()
            UserDefaults.standard.set(true, forKey: "isMuted")
         }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search