I have a functional countdown timer.
The problem is that I need to continue the countdown when the user puts the app in the background. Or suspends the app? I am no
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
}
}
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:
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.)
When you start your timer, record the current NSDate. Then, when your app returns to the foreground or gets re-launched, 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.
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")
}
}
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
}