Timer with Background in Swift

Asked by At

I want to do Timer application, it takes a time when start Activity and When press Home timer will continue to works, but When I use below code it works correctly at foreground but When I press home and it works background, seconds is greater than 60 and, In this case, it’s giving me weird numbers like 00:01:75. Do you know how to resolve this bug? Thanks in advance.

override func viewDidLoad() {
 super.viewDidLoad()

   NotificationCenter.default.addObserver(self, selector: #selector(pauseWhenBackground(noti:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
   NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(noti:)), name: UIApplication.willEnterForegroundNotification, object: nil)
}

@objc func willEnterForeground(noti: Notification) {
    if let savedDate = UserDefaults.standard.object(forKey: "savedTime") as? Date {
        (diffHrs, diffMins, diffSecs) = AddWorkTime.getTimeDifference(startDate: savedDate)

        self.refresh(hours: diffHrs, mins: diffMins, secs: diffSecs)
    }
}

static func getTimeDifference(startDate: Date) -> (Int, Int, Int) {
    let calendar = Calendar.current
    let components = calendar.dateComponents([.hour, .minute, .second], from: startDate, to: Date())
    return(components.hour!, components.minute!, components.second!)
}

func refresh (hours: Int, mins: Int, secs: Int) {
    self.hrs += hours
    self.min += mins
    self.sec += secs
     self.time.text = String(format: "%02d : %02d : %02d", self.hrs, self.min, self.sec)
     self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(AddWorkTime.updateLabels(t:))), userInfo: nil, repeats: true)

}

@objc func updateLabels(t: Timer) {
    if (self.sec == 59) {
        self.min += 1
        self.sec = 0
    }
    if (self.min == 60) {
        self.hrs += 1
        self.min = 0
    }else{
        self.sec += 1
    }

    self.time.text = String(format: "%02d : %02d : %02d", self.hrs, self.min, self.sec)
}

@objc func pauseWhenBackground(noti: Notification) {
    self.timer.invalidate()
    let shared = UserDefaults.standard
    shared.set(Date(), forKey: "savedTime")
}

func resetContent() {
    self.removeSavedDate()
    timer.invalidate()
    self.time.text = "00 : 00 : 00 "
    self.sec = 0
    self.min = 0
    self.hrs = 0
}

func removeSavedDate() {
    if (UserDefaults.standard.object(forKey: "savedTime") as? Date) != nil {
        UserDefaults.standard.removeObject(forKey: "savedTime")
    }
}

1 Answers

0
Agisight On Best Solutions

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
}

For example, call method below where you want or check your timer.

func registerBackgroundTask() {
    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + 5, qos: .background) {
            print("fasdf")
        }
}