我试图在计时器的倒数达到0后触发本地通知。 计时器启动后,我将通知设置为在完成日期触发(我通过计算当前时间间隔+倒数时间来获取通知)。
当视图转到背景时,我保存倒计时和完成日期的值。一旦视图变为前景,我便会访问这些值并计算现在的时间是否高于完成日期,否则,我将计算差值以了解倒计时的新值。
我的问题是,即使它似乎可以正常工作,但仅在我离开视图一次后,它才能正确执行。如果我多次进入后台或再次进入该应用程序的另一个视图来离开该视图,则我认为该通知是在正确的时间触发的,但我监视计时器的标签不同步。 有时会有1秒钟的延迟,但是如果我多次离开应用程序,从标签到通知我都会有巨大的延迟差异。
我无法弄清楚自己做错了什么或想念什么。 有人可以帮我吗?
顺便说一句,我是自学成才地尝试构建我的第一个应用程序,没有其他人可以从我那里得到帮助。unsync example
代码示例
观察者
//I have two observers in viewDidLoad. One for when the app enters the background and one for when the app comes to the foreground
//gets notified from applicationWillEnterForeground from AppDelegate
let wakeApp = Notification.Name("wakeApp")
NotificationCenter.default.addObserver(self, selector: #selector(wakeUp(notification:)), name: wakeApp, object: nil)
//gets notified from applicationWillResignActive from AppDelegate
let resignActive = Notification.Name(rawValue: "resignActive")
NotificationCenter.default.addObserver(self, selector: #selector(resignActivity), name: resignActive, object: nil)
//This is what observers do.
@objc func wakeUp(notification: Notification) {
loadSavedUserDefaults()
}
//viewWillDisapear() does the same as resignActivity() because resignActivity() is not triggered by switching views and I had to create
//the observer with the method resignActivity() because when the app goes to the background it does not trigger the viewWillDisapear()
@objc func resignActivity() {
saveTimerState()
timer.invalidate()
}
加载方法
fileprivate func loadSavedUserDefaults() {
guard let savedUserDefaults = UserDefaults.standard.object(forKey: taskName) as? Data else {
print("Unable to load user defaults")
return
}
do {
let savedTask = try JSONDecoder().decode(SavedTask.self, from: savedUserDefaults)
guard savedTask.isRunning else {
if savedTask.countdown > 0 {
countdown = savedTask.countdown
} else {
countdown = 0
btStartPause.setTitle("Restart", for: .normal)
}
calculatePercentage()
lbDuration.text = TimeInterval(countdown).stringFromTimeInterval()
return
}
isRunning = savedTask.isRunning
let date = Date()
countdown = date - savedTask.date
if countdown > 0 {
calculatePercentage()
btStartPause.setTitle("Pause", for: .normal)
lbDuration.text = TimeInterval(countdown).stringFromTimeInterval()
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateUI), userInfo: nil, repeats: true)
} else {
print("Current date is superior than scheduled date")
countdown = 0
calculatePercentage()
btStartPause.setTitle("Restart", for: .normal)
lbDuration.text = TimeInterval(countdown).stringFromTimeInterval()
}
} catch {
print("error decoding saved data")
}
}
保存方法
func saveTimerState() {
let savedTask = SavedTask.init(isRunning: isRunning, date: date, countdown: countdown)
do {
let taskData = try JSONEncoder().encode(savedTask)
UserDefaults.standard.set(taskData, forKey: taskName )
} catch {
print(error.localizedDescription)
}
}