Search code examples
iosswiftmultithreadingnstimer

NSTimer is being triggered only one time after invalidating and reinitializing


I have the following function setPath() which is called whenever the user taps on a button:

var loadSuccessfulTimer: Timer? = nil
func setPath(index: Int) {

    self.loadSuccessfulTimer?.invalidate()
    self.loadSuccessfulTimer = nil

    print("setting path")

    self.pause(releaseAudioSession: false)

    self.reset(index: index)
    let song = DataManager.getInstance().getQueueSong(index: index)
    superpowered.setPath(song.url, true)


    self.loadSuccessfulTimer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(checkLoadSucess), userInfo: nil, repeats: true)
    self.loadSuccessfulTimer!.fire()
}

@objc func checkLoadSucess() {
    let status = self.superpowered.getLoadSuccessful()
    print(status)
    if(status != -1) {
        self.loadSuccessfulTimer?.invalidate()
        self.loadSuccessfulTimer = nil

        if(status == 1){
            print("success")
        } else if(status == 2){
            print("failed")
        }
    }
}

So whenever the setPath() function gets called, I want the timer to trigger every 0.2 seconds to check on a the value of status = self.superpowered.getLoadSuccessful(). The variable status would have values -1, 1, 2 I want to stop the timer when it's either 1 or 2. However, the following scenario is happening:

On the first tap it is working as expected and printing the following:

setting path
-1
-1
-1
-1
-1
-1
1
success

On the second tap the timer is only triggered one time (I guess it is from the .fire()) and the following is being printed:

setting path
-1

I tried to look up what might be going wrong, but all I could see was this is the recommended way of using a Timer.

Update

The second time setPath() is being called from DispatchQueue.global(), maybe this is related to the issue.


Solution

  • NSTimer requires run loop to work properly. The main queue has a run loop for free, for other queues you need to make sure run loop is available.

    Make sure you read the documentation: https://developer.apple.com/documentation/foundation/nstimer

    Also, remember to invalidate NSTimer object from the same run loop (thread) is has been created (scheduled) from.