OriginalAlchemist
OriginalAlchemist

Reputation: 411

Swift: Issue with my NSTimer?

So in general terms, this is what i want my program to do: music will play, randomly generate a number between 3 and 12, then set a timer according to that number, when the timer is finished stop the music for 1 second, then after that one second, play the music again(and repeat the process, generate random number...)

This is the code I have written to do so, it works great the first run, but the second run it starts calling the functions at a faster rate(not following the timer) and sometimes in a different order(you can test this by looking at the print out)

var randomTimeInteger = Int()
var stopMusicTimer = NSTimer()
var startMusicTimer = NSTimer()

override func viewDidLoad(){
    playMusic()
}

 //Call to get random interger
func generateRandomInteger(){
    print("Inside generate random integer")
    let lower = 3
    let upper = 12
    randomTimeInteger = lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    print("Random Integer is : \(randomTimeInteger)")
    initiateTimer()
}

//Start the timer
func initiateTimer() {
    print("Inside initate Timer")
    //Set Timer
    stopMusicTimer = NSTimer.scheduledTimerWithTimeInterval(Double(randomTimeInteger), target: self, selector: "stopMusic", userInfo: nil, repeats: true)
}

//Stop the music
func stopMusic(){
    print("Inside stop music")
    GameViewController.backgroundAudio?.stop()

    startMusicTimer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: "playMusic", userInfo: nil, repeats: true)
}


func playMusic(){
    print("Inside play music")
    GameViewController.backgroundAudio?.play()
    generateRandomInteger()
}

Any idea what the problem is? Or if there is a better way to do so? PLEASE HELP!

Upvotes: 1

Views: 59

Answers (2)

CouchDeveloper
CouchDeveloper

Reputation: 19098

There are really numerous viable approaches.

Starting from the top, I would sketch the design as follows:

func playMusic(completion: (ErrorType?)->()) {
    play(randomDuration()) { error in
        if error != nil {
            completion(error)
            return
        }
        delay(1.0, f: play)
    }
}

func randomDuration() -> Double {...}

func play(duration: Double, completion: (ErrorType?)->()) {
    let player = Player(...)
    player.resume()
    delay(duration) {
        player.suspend()
        completion(nil)
    }
}

Function delay(_:f:) is implemented in terms of dispatch_after.

You will probably notice, that playMusic runs indefinitely. This is by your requirements, but in practice you need a way to stop it.

Upvotes: 0

gnasher729
gnasher729

Reputation: 52530

You have one timer that tries to stop the music every 3 to 12 seconds. And sometimes you create a timer that tries to start the music every 3 seconds. And sometimes you create more of these timers. So eventually you have lots and lots of timers that try starting and stopping the music at random time.

To stop a repeating timer, call invalidate.

And don't initialise the timers as you do, NSTimer() returns nothing useful. Just declare the variables as NSTimer?

Upvotes: 3

Related Questions