用Swift实现后台计时器

4

我想做一个计时器应用,当启动Activity并按下主页键时,计时器将继续工作。但是使用以下代码时,在前台时可以正确运行,但在后台时,秒数会变得大于60,并且在这种情况下,它会给我一些奇怪的数字,如00:01:75。你知道如何解决这个错误吗?谢谢。

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个回答

0
请确保在xCode中开启后台模式并设置所需的值。奇怪的是,即使关闭了后台模式,这段代码仍然有效。似乎在AppDelegate中设置application.beginBackgroundTask {}后,任何计时器都会起作用。
我使用以下代码:
在AppDelegate中添加以下代码:
func applicationDidEnterBackground(_ application: UIApplication) {

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

例如,在您想要的地方调用下面的方法或检查您的计时器。
func registerBackgroundTask() {
    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + 5, qos: .background) {
            print("fasdf")
        }
}

1
我在ViewDidLoad中禁用了pauseWhenBackground和willEnterForeground,我添加了registerBackgroundTask(),并启用了后台模式,现在它可以正常工作。谢谢。 - Diego
我收到了这个消息:由于信号9终止,应用程序已关闭。 - Diego
这取决于您在哪个线程中调用了什么……没有任何上下文,我也不知道。 - Agisight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接