Continue countdown timer when app is running in background/suspended

不问归期 提交于 2019-11-30 10:12:00

What I suggest is cancel the timer and store a NSDate when the app goes to the background. You can use this notification to detect the app going to the background:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseApp", name: UIApplicationDidEnterBackgroundNotification, object: nil)

Then cancel the timer and store the date:

func pauseApp(){
    self.stop() //invalidate timer
    self.currentBackgroundDate = NSDate()
}

Use this notification to detect the user coming back:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "startApp", name: UIApplicationDidBecomeActiveNotification, object: nil)

Then calculate the difference from the stored date to the current date, update your counter and start the timer again:

func startApp(){
    let difference = self.currentBackgroundDate.timeIntervalSinceDate(NSDate())
    self.handler(difference) //update difference
    self.start() //start timer
}

You shouldn't do that. A running timer keeps the device's processor running at full power, which is bad.

Only certain types of apps are allowed to actually run code indefinitely from the background, e.g. VOIP apps and music apps.

A couple of options:

  1. Set up a local notification for a future date (which will send a message to your app, or re-launch it if it was no longer running.)

  2. When you start your timer, record the current NSDate. Then, when your app returns to the foreground or gets re-launched, fetch compare the current date to the saved date, figure out the amount of time that's elapsed, and decide if your timer is finished yet.

Try this instead.. this code updates the time when app comes back from background/suspend and in active state..

class ProgressV: UIView {

var timer: NSTimer!
var expirationDate = NSDate()

//Set the time that you want to decrease..
var numSeconds: NSTimeInterval = 36000.0 // Ex:10:00 hrs

func startTimer()
{
    // then set time interval to expirationDate…
    expirationDate = NSDate(timeIntervalSinceNow: numSeconds)
    timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(updateUI(_:)), userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)

}
func updateUI(timer: NSTimer)
{
  // Call the currentTimeString method which can decrease the time..
   let timeString = currentTimeString()
   labelName.text = timeString
}
func currentTimeString() -> String {
    let unitFlags: NSCalendarUnit = [.Hour, .Minute, .Second]
    let countdown: NSDateComponents = NSCalendar.currentCalendar().components(unitFlags, fromDate: NSDate(), toDate: expirationDate, options: [])

    var timeRemaining: String
    if countdown.hour > 0
    {
        timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
    }
    else {
        timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
    }
    return timeRemaining
}

}

Be sure that you turn on the background mode and set needed values in xCode. It is strange, but even if background mode is turned off, this code works. It seems to be work any timers after setting application.beginBackgroundTask {} in AppDelegate.

I use this code:

In AppDelegate add code below:

func applicationDidEnterBackground(_ application: UIApplication) {

    application.beginBackgroundTask {} // allows to run background tasks
}

And call method below where you want.

func registerBackgroundTask() {
    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + 5, qos: .background) {
            print("fasdf")
        }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!