title: Simple service in Swift, persists, foreground only?
body: <p>I very simply want something to run</p>
  
  <ul>
  <li>every say 20 seconds</li>
  <li>simply only when the app is foreground (explicitly not run when background)</li>
  <li>obviously, it would be more elegant if you don't have to bother following the app going in and out of foreground</li>
  <li>The issue, I was amazed to learn with <code>scheduleRepeating</code> that, in the simulator, it <em>keeps running</em> when the app is in background: that doesn't give me confidence that it explicitly <em>won't run</em> in background on (some? whatever?) devices</li>
  <li>The issue, I discovered that on a device, testing with as many generations / OS as possible, <code>scheduleRepeating</code> annoyingly <em>will</em> (in some? all? cases) run <em>one time only</em> when the app goes into background.  That is to say: it runs "one more time" once the app goes to background. Suck.</li>
  </ul>
  
  <p>So to repeat: in iOS how to have a simple service that runs every 20 seconds, and, only runs when the app is in a foreground, and, it is fuss-free .. ideally you don't have to restart it, check it or anything during the life of the app...</p>
  
  <p>really what is the best way to do such a simple thing?</p>
  
  <p>This is my (seemingly) working solution, which is inelegant. Surely there is a built-in way, or something, to do such an obvious thing in iOS??</p>
  
  <pre><code>open class SomeDaemon {
  
      static let shared = SomeDaemon()
      fileprivate init() { print("SomeDaemon is running") }
      var timer: DispatchSourceTimer? = nil
      let gap = 10   // seconds between runs
  
      func launch() {
  
          // you must call this from application#didLaunch
          // harmless if you accidentally call more than once
          // you DO NOT do ANYTHING on app pause/unpause/etc
  
          if timer != nil {
  
              print("SomeDaemon, timer running already")
              return
          }
  
          timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
          timer?.scheduleRepeating(deadline: .now(), interval: .seconds(gap))
          timer?.setEventHandler{ self. doSomeThing() }
          timer?.resume()
      }
  
      private func doSomeThing() {
  
          if UIApplication.shared.applicationState != .active {
  
              print("avoided infuriating 'runs once more in bg' problem.")
              return
          }
  
          // actually do your thing here
      }
  }
  </code></pre>