froggomad
froggomad

Reputation: 1915

Timer not stopping on segue

I'm instantiating a timer like this:

func runTimer() {
  DispatchQueue.main.async {
    if self.timer.isValid == false {
      self.timer = Timer.scheduledTimer(timeInterval: 0.025, target: self, selector: (#selector(ResultVCViewController.updateTimer)), userInfo: nil, repeats: true)
      RunLoop.current.add(self.timer, forMode: .commonModes)          
      }
    }
  }

and deallocating it like this:

func stopTimer() {
  DispatchQueue.main.async {
    if self.timer.isValid {
      self.timer.invalidate()
      self.isTimerRunning = false
      print("stopped timer")
    } else {
      print("timer isn't running!")
    }
  }
}

When called like this, stopTimer() isn't being called (no console output , timer still running, if I add a breakpoint, it's ignored but the segue is performed):

@IBAction func aboutLicensebtn(_ sender: UIBarButtonItem) {
  //debug
  stopTimer()
  performSegue(withIdentifier: "AboutLicense", sender: nil)
}

And this works as expected:

@IBAction func goBack(_ sender: UIBarButtonItem) {
  stopTimer()
  self.dismiss(animated: true, completion: nil)
}

How can I stop the timer when performing a segue?

Edit: The timer stops when put into viewDidDisappear but I don't want this behavior.

Edit: I tried performing the segue on main as well, but the result is unchanged.

Clarification on why I'm starting and stopping the timer the way I am:

It's added to a RunLoop to use for .commonModes so the timer doesn't stop when the view is scrolled.

It's started and stopped on main to ensure its being started and stopped on the same thread.

Upvotes: 1

Views: 165

Answers (1)

vadian
vadian

Reputation: 285240

Do not add a scheduled timer to a runloop.

The most reliable way to start and stop a timer is to use an optional property and check this (the dispatch to the main queue is not needed at all):

var timer : Timer?

func runTimer() {
    if timer == nil {
       timer = Timer.scheduledTimer(timeInterval: 0.025, 
                     target: self, 
                     selector: #selector(updateTimer), 
                     userInfo: nil, 
                     repeats: true)
    }
}

func stopTimer() {
    if timer != nil {
      timer!.invalidate()
      timer = nil
      print("stopped timer")
    } else {
      print("timer isn't running!")
    }
}

Upvotes: 3

Related Questions