如何使用 NSUserDefaults 保存 NSTimer? Swift

How to save NSTimer using NSUserDefaults? Swift

我想使用 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)"
}
}