我想用NSUserDefaults保存一个计时器来完成我的目标。不幸的是,当我尝试使用NSUserDefaults保存NSDate()时,它变为静态的,并且不会继续计数。我做错什么了吗?我的目标是让计时器仍然工作,不管它是转到后台还是被终止。它应该节省当前时间,并将其与剩余时间进行比较。这是我目前的密码。解决这个问题的其他代码在OBJ C中,并且使用了didEnterBackground,这是不必要的。
func startTimer() {
// then set time interval to expirationDate…
expirationDate = NSDate(timeIntervalSinceNow: 86400 )
dateTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(QOTDVC.updateUI(timer:)), userInfo: nil, repeats: true)
RunLoop.current.add(dateTimer, forMode: RunLoopMode.commonModes)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "TimerAdded"), object: nil)
}
func updateUI(timer: Timer)
{
// Call the currentTimeString method which can decrease the time..
let timeString = currentTimeString()
timerLabel.text = "\(timeString)"
}
func currentTimeString() -> DateComponents {
let unitFlags: Set<Calendar.Component> = [.hour, .minute, .second]
let countdown: DateComponents = Calendar.current.dateComponents(unitFlags, from: defaults.object(forKey: currentTime.description) as! Date, to: expirationDate as Date)
print("this is the \(countdown)")
if countdown.second! > 0 {
} else {
dateTimer.invalidate()
}
return countdown
}
最佳答案
这是我的完整代码示例。我希望这是你想要的。
import UIKit
protocol UserDefaultsTimerDelegate {
func timerAction(timer: Timer, secondsToEnd:Int)
}
class UserDefaultsTimer {
static var delegate: UserDefaultsTimerDelegate?
class var timerEndDate: Date? {
get {
return UserDefaults.standard.value(forKey: "timerEndDate") as! Date?
}
set (newValue) {
UserDefaults.standard.setValue(newValue, forKey: "timerEndDate")
}
}
class var timerInited: Bool {
get {
if let _ = timerEndDate {
return true
} else {
return false
}
}
}
class func setTimer(date: Date, setDateOnlyIfCurrenTimerIsOver: Bool) {
if !setDateOnlyIfCurrenTimerIsOver {
timerEndDate = date
} else {
if !timerInited {
timerEndDate = date
} else {
let difference = timerEndDate!.seconds(from: Date())
if (difference <= 0) {
timerEndDate = date
}
}
}
}
class func resetTimer() {
timerEndDate = nil
}
class func resumeTimer() {
if timerInited {
NSLog("timer end date:\(timerEndDate)")
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(action(timer:)), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
}
}
@objc class func action(timer: Timer) {
if let timerEndDate = timerEndDate {
let difference = timerEndDate.seconds(from: timer.fireDate)
if let delegate = delegate {
delegate.timerAction(timer: timer, secondsToEnd: difference)
}
NSLog("timer: \(difference)")
if (difference <= 0) {
timer.invalidate()
resetTimer()
}
} else {
timer.invalidate()
resetTimer()
}
}
}
extension Date {
/// Returns the amount of years from another date
func years(from date: Date) -> Int {
return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
}
/// Returns the amount of months from another date
func months(from date: Date) -> Int {
return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
}
/// Returns the amount of weeks from another date
func weeks(from date: Date) -> Int {
return Calendar.current.dateComponents([.weekOfYear], from: date, to: self).weekOfYear ?? 0
}
/// Returns the amount of days from another date
func days(from date: Date) -> Int {
return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
}
/// Returns the amount of hours from another date
func hours(from date: Date) -> Int {
return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
}
/// Returns the amount of minutes from another date
func minutes(from date: Date) -> Int {
return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
}
/// Returns the amount of seconds from another date
func seconds(from date: Date) -> Int {
return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
}
/// Returns the a custom time interval description from another date
func offset(from date: Date) -> String {
if years(from: date) > 0 { return "\(years(from: date))y" }
if months(from: date) > 0 { return "\(months(from: date))M" }
if weeks(from: date) > 0 { return "\(weeks(from: date))w" }
if days(from: date) > 0 { return "\(days(from: date))d" }
if hours(from: date) > 0 { return "\(hours(from: date))h" }
if minutes(from: date) > 0 { return "\(minutes(from: date))m" }
if seconds(from: date) > 0 { return "\(seconds(from: date))s" }
return ""
}
}
class ViewController: UIViewController, UserDefaultsTimerDelegate {
var label = UILabel(frame: CGRect(x: 40, y: 40, width: 60, height: 20))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
label.text = ""
label.textColor = UIColor.black
view.addSubview(label)
UserDefaultsTimer.delegate = self
UserDefaultsTimer.setTimer(date: Date(timeIntervalSinceNow: 50), setDateOnlyIfCurrenTimerIsOver: true)
UserDefaultsTimer.resumeTimer()
}
func timerAction(timer: Timer, secondsToEnd: Int) {
label.text = "\(secondsToEnd)"
}
}