title: Swift: another timer starting when application enters background
body: <p>I've been struggling to figure this out for a few days: I need to create a timer that the user can't kill, so once they start it, even if they kill the app or it enters background, it will pick up where it left off, and to achieve this I am saving the date when the app terminated and then calculating the difference, so that part works fine.</p>
  
  <p>The problem I keep running into however is that a second timer seems to start if I minimise the app and bring it back. I'm not sure how timers are managed in the background, but nothing of what I tried (calling timer.invalidate() when applicationWillResignActive gets called, calling it in deinit() ) seems to work. The behaviour I see after this is that the timer will count like this: 80 - 78 - 79 - 76 - 77..</p>
  
  <p>There's also a problem where the timer will sometime run past the time it's supposed to run for after killing the app, but I can't find the exact cause for that because it doesn't always happen.</p>
  
  <p>Any idea what I'm doing wrong?</p>
  
  <p><strong>Thanks a lot.</strong></p>
  
  <pre><code>class Focus: UIViewController {
  
  // MARK: Variables
  var timer = Timer()
  let timeToFocus = UserDefaults.standard.double(forKey: "UDTimeToFocus")
  let currentFocusedStats = UserDefaults.standard.integer(forKey: "UDFocusStats")
  
  
  // MARK: Outlets
  @IBOutlet weak var progress: KDCircularProgress!
  @IBOutlet weak var timeLabel: UILabel!
  @IBOutlet weak var focusTimeLabel: UILabel!
  @IBOutlet weak var stepNameLabel: UILabel!
  @IBOutlet weak var focusAgain: UIButton!
  @IBOutlet weak var allDone: UIButton!
  @IBOutlet weak var help: UIButton!
  @IBOutlet weak var dottedCircle: UIImageView!
  
  
  // MARK: Outlet Functions
  @IBAction func helpTU(_ sender: Any) { performSegue(withIdentifier: "ToFocusingHelp", sender: nil) }
  @IBAction func helpTD(_ sender: Any) { help.tap(shape: .rectangle) }
  
  
  @IBAction func allDoneTU(_ sender: Any) {
      UserDefaults.standard.set(false, forKey: "UDFocusIsRunning")
      UserDefaults.standard.set(false, forKey: "UDShouldStartFocus")
      completeSession()
      hero(destination: "List", type: .zoomOut)
  }
  
  @IBAction func allDoneTD(_ sender: Any) { allDone.tap(shape: .rectangle) }
  
  
  @IBAction func focusAgainTU(_ sender: Any) {
      UserDefaults.standard.set(currentFocusedStats + Int(timeToFocus), forKey: "UDFocusStats")
      UserDefaults.standard.set(true, forKey: "UDShouldStartFocus")
      initFocus()
  }
  
  @IBAction func focusAgainTD(_ sender: Any) { focusAgain.tap(shape: .rectangle) }
  
  
  // MARK: Class Functions
  @objc func initFocus() {
  
      var ticker = 0.0
      var angle = 0.0
      var duration = 0.0
  
       if UserDefaults.standard.bool(forKey: "UDShouldStartFocus") == true {
          UserDefaults.standard.set(Date(), forKey: "UDFocusStartDate")
          UserDefaults.standard.set(false, forKey: "UDShouldStartFocus")
          ticker = timeToFocus
          duration = timeToFocus
          angle = 0.0
          print("starting")
       } else {
          let elapsedTime = difference(between: UserDefaults.standard.object(forKey: "UDFocusStartDate") as! Date, and: Date())
          let timeLeft = timeToFocus - elapsedTime
          ticker = timeLeft
          duration = timeLeft
          angle = elapsedTime / (timeToFocus / 360)
       }
  
      // Timer
      let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
          if ticker &gt; 0 {
              self.timeLabel.text = "\(Int(ticker))s"
              ticker -= 1
          }
      }
      timer.fire()
  
      // Progress Circle
      progress.animate(fromAngle: angle, toAngle: 360, duration: duration) { completed in
          if completed { self.completeSession() }
      }
  
  
      // UI Changes
      allDone.isHidden = true
      focusAgain.isHidden = true
      help.isHidden = false
  }
  
  
  func completeSession() {
      // The timer gets fired every time, but this will invalidate it if it's complete
      timer.invalidate()
      timeLabel.text = "Done"
      help.isHidden = true
      allDone.isHidden = false
      focusAgain.isHidden = false
  }
  
  
  // MARK: viewDidLoad
  override func viewDidLoad() {
  
      initFocus()
  
      allDone.isHidden = true
      focusAgain.isHidden = true
  
      if timeToFocus &lt; 3600 { focusTimeLabel.text = "Focusing for \(Int(timeToFocus/60)) minutes" }
      else if timeToFocus == 3600 { focusTimeLabel.text = "Focusing for \(Int(timeToFocus/60/60)) hour" }
      else { focusTimeLabel.text = "Focusing for \(Int(timeToFocus/60/60)) hours" }
  
      stepNameLabel.text = UserDefaults.standard.string(forKey: "UDSelectedStep")
  
      // This resumes the timer when the user sent the app in the background.
      NotificationCenter.default.addObserver(self, selector: #selector(self.initFocus), name: NSNotification.Name(rawValue: "WillEnterForeground"), object: nil)
      NotificationCenter.default.addObserver(self, selector: #selector(self.fadeProgress), name: NSNotification.Name(rawValue: "WillEnterForeground"), object: nil)
  
  }
  
  @objc func fadeProgress(){
  
      // This function is called both when the view will enter foreground (for waking the phone or switching from another app) and on viewWillAppear (for starting the app fresh). It will fade the progress circle and buttons to hide a flicker that occurs.
      timeLabel.alpha = 0
      dottedCircle.alpha = 0
      progress.alpha = 0
      allDone.alpha = 0
      focusAgain.alpha = 0
  
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
          UIButton.animate(withDuration: 0.5, animations: {
              self.timeLabel.alpha = 1
              self.dottedCircle.alpha = 1
              self.progress.alpha = 1
              self.allDone.alpha = 1
              self.focusAgain.alpha = 1
  
          })
      })
  }
  
  // MARK: viewWillAppear
  override func viewWillAppear(_ animated: Bool) { fadeProgress() }
  }
  </code></pre>