Swift 3 - How to Make Timer Work in Background

Run timer in background

It's possible through a token that identifies a request to run in the background.

Like this: var bgTask = UIBackgroundTaskIdentifier()

Here is how to use it:

var bgTask = UIBackgroundTaskIdentifier()
bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
UIApplication.shared.endBackgroundTask(bgTask)
})
let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(notificationReceived), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.defaultRunLoopMode)

I hope it would be useful!

Background timer running

Until iOS 12, you could not been able to run your app in background mode, but from iOS 13 (beta) you can.
Apple has added framework BackgroundTasks which can add ability to do some task in background mode.

https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler

Swift 3 - How to keep my timer counting even in background?

Okay, so without going to in-depth into your code it appears that you're using a Timer.scheduledTimer to manually decrement the time set by the user every second.

This is not a good technique as you've found out - it only works when you know you have absolute control over the timing of your application.

Instead, what you should do is store the time when the user starts the alarm, the projected end time, and run a timer to just periodically update the UI.

(My code here isn't perfect, but it should point you in the right direction for solving the problem of keeping a timer running in the background.)

ex.

class ViewController: UIViewController {
// this is pseudo-code as I don't have my compiler open :(
let start: Date!
let end: Date!

func selectionCuisson(selection: Int) {

...

start = Date()
end = Date(timeInterval: tempsCuisson, since: start)
}

}

Then you create a timer that will just update the UI.

// You can set this to be faster than the increment, for a smoother UI experience
// put in compteur()? I think
timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(ViewController.incrementer), userInfo: nil, repeats: true)
timer.fire()

...

func incrementer() {
let tempsCuisson = end - start
if tempsCuisson < 0 {
// End your Timing Function here
timer.invalidate()
...
lecteur.play()
} else {
minuteurLabel.text = minuteurString(temps: tempsCuisson)
}
}

You can also set a Local Notification to go off when the app goes into the background using the end date

// when the app becomes inactive
let notification = UILocalNotification()
...
notification.fireDate = end
UIApplication.shared.scheduleLocalNotification(notification)


Related Topics



Leave a reply



Submit