Search code examples
iosswiftnstimeruilocalnotification

How to update a UILabel timer after being in background


I am trying to build a simple timer which works just fine when it is active. The problem is, If I quit out of the application at 30 seconds left and come back 10 seconds later, it shows that I have roughly 28 seconds left on my timer. Then on top of that, my notification timing gets messed up. I've been trying many different ways to solve the problem but to no avail. Can anyone help with this?

import UIKit
import AVFoundation
import Foundation
import UserNotifications

class TimerController: UIViewController, UNUserNotificationCenterDelegate {

//MARK: - Variables and Constants

var Minutes = 10.0
var audioPlayer = AVAudioPlayer()
let vc = ViewController()
var isGrantedAccess = false
private var timer = Timer()
let timeInterval = 0.1

//MARK: - IBOutlet
@IBOutlet weak var label: UILabel!
@IBOutlet weak var sliderOutlet: UISlider!
@IBOutlet weak var startOutlet: UIButton!
@IBOutlet weak var stopOutlet: UIButton!


//MARK: - Functions

//MARK: - Notification Alert Functions

func startTimer() {

}

func stopTimer(){
    //shut down timer
    timer.invalidate()
    //clear out any pending and delivered notifications
    UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    UNUserNotificationCenter.current().removeAllDeliveredNotifications()
}

func sendNotification() {

        let content = UNMutableNotificationContent()
        content.title = "Timer Finished"
        content.body = "Your escort should be here"
        content.sound = UNNotificationSound.default()
        content.categoryIdentifier = "timer.category"

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Minutes, repeats: false)
        let request = UNNotificationRequest(identifier: "timer.request", content: content, trigger: trigger)
        UNUserNotificationCenter.current().add(request) { (error) in
            if let error = error{
                print("Error posting notification:\(error.localizedDescription)")

        }
    }
}


func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    if response.actionIdentifier == "stop.action"{
        stopTimer()
    }
    completionHandler()
}

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert,.sound])
}




//MARK: - UIButtons
@IBAction func slider(_ sender: UISlider)
{
    Minutes = Double(sender.value)
    label.text = String(format: "%.0f", Minutes) + " Minutes"
}


@IBAction func start(_ sender: AnyObject) {

    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(counter), userInfo: nil, repeats: true)

    sliderOutlet.isHidden = true
    startOutlet.isHidden = true
    self.sendNotification()

}

func counter() {
    DispatchQueue.main.async {

    self.Minutes -= 1
    self.label.text = String(format: "%.0f", self.Minutes) + " Minutes"
    }
    if (Minutes == 0)
    {
        timer.invalidate()

        sliderOutlet.isHidden = false
        startOutlet.isHidden = false


    }
}



@IBAction func stop(_ sender: AnyObject)
{
    timer.invalidate()
    Minutes = 0
    sliderOutlet.setValue(10, animated: true)
    label.text = "0 Minutes"

    audioPlayer.stop()

    sliderOutlet.isHidden = false
    startOutlet.isHidden = false
}



override func viewDidLoad()
{
    super.viewDidLoad()

    print(vc.isGrantedAccess)

    do
    {
        let audioPath = Bundle.main.path(forResource: "1", ofType: ".mp3")
        try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
    }
    catch
    {
        //ERROR
    }

}

Solution

  • Store Date() in NSUserDefaults when you go to background in

    func applicationDidEnterBackground(_ application: UIApplication) {}
    

    then calculate difference between new Date when you go to foreground in

    func applicationWillEnterForeground(_ application: UIApplication) {}