2016-09-28 4 views
0

Я хочу сохранить таймер, используя NSUserDefaults, чтобы выполнить мою цель. К сожалению, когда я пытаюсь сохранить NSDate() с помощью NSUserDefaults, он становится статическим и не будет продолжать подсчет. Я делаю что-то неправильно? Опять же, моя цель заключается в том, что таймер все еще работает независимо от того, пошел ли он на задний план или закончил. Он должен сохранить текущее время и сравнить его с тем, сколько времени осталось. Вот мой код до сих пор. Другой код, рассматривающий эту проблему, находится в OBJ C и используется didEnterBackground, что необязательно.Как сохранить NSTimer с помощью NSUserDefaults? Swift

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 
} 
+2

Вы не можете сохранить таймер в 'NSUserDefaults'. См. Этот вопрос: http://stackoverflow.com/questions/22628922/how-to-run-nstimer-in-background-beyond-180sec-in-ios-7 – random

+0

Я читал: http://stackoverflow.com/questions/39753403/how-to-save-nstimer-using-nsuserdefaults-swift? Noredirect = 1 # comment66803063_39753403, и это, кажется, говорит иначе. Я просто не понимаю, почему он остается статичным. –

+1

Поскольку ваш таймер подсчитывает секунды, почему вы не используете системное время? Сохраните текущее время и прошедшие секунды со своего счетчика, когда приложение перейдет на задний план. – vadian

ответ

1

Вот мой полный пример кода. Надеюсь, это то, что вы хотели.

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)" 
} 
} 
+0

Итак, вы проверили это решение? –