43

I am building a stopwatch application and I need to store the start date before the user closes the application and need to retrieve it when the user opens the application again.

So for example if the user starts the stopwatch and then closes the application and then after some time opens the application again the app should add the time between the opening and closing to the running time if the stopwatch was running.

I have created two functions in my viewcontroller that handle this. Here's the code:

    override func viewWillAppear(animated: Bool)
    {

      let startTimedefault:NSUserDefaults = NSUserDefaults.standardUserDefaults()

      let startTimesaved:NSDate = startTimedefault.objectForKey("start time") // This line is buggy


      if(launchBool == true)
      {      
         timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "fireStopWatch", userInfo: nil, repeats: true)

         startTime = startTimesaved
      }

      if(launchBool == false)
      {
         timer.invalidate()
      }

    }

    override func viewWillDisappear(animated: Bool)
    {
       NSUserDefaults.standardUserDefaults().setObject(launchBool, forKey: "Start/Stop")
       NSUserDefaults.standardUserDefaults().setObject(startTime, forKey: "start time")
       NSUserDefaults.standardUserDefaults().setObject(elapsedTime, forKey: "elapsed time")
    }

I have gone through a couple of posts here on StackOverflow :

What's the optimum way of storing an NSDate in NSUserDefaults?

iOS - Not able to store NSDate into NSUserDefaults

Community
  • 1
  • 1
Atharva Vaidya
  • 754
  • 1
  • 5
  • 12

3 Answers3

106

Set your date object as follows:

UserDefaults.standard.set(Date(), forKey:"yourKey")

Retrieve it using:

UserDefaults.standard.object(forKey: "yourKey") as? Date

Date will be optional of course, because it might never have been set.

Mike Sand
  • 2,750
  • 14
  • 23
Sujith Thankachan
  • 3,508
  • 2
  • 20
  • 25
  • 7
    Or as from Swift 1.2 `NSUserDefaults.standardUserDefaults().objectForKey("yourKey") as! NSDate` – Viesturs Knopkens Jun 10 '15 at 13:49
  • 14
    This will crash if `yourKey` isn't already saved to userDefaults. Should use `as? NSDate` instead – Inn0vative1 Feb 28 '17 at 11:10
  • @Inn0vative1 sure, never force-unwrap an optional if you're not sure there is a value – Dannie P Jul 26 '17 at 19:02
  • @Inn0vative1 So came across this page, and 2 1/2+ years after your comment (and 5 years after it's answer!) I have edited this to specify you should retrieve an optional. UserDefaults is always going to be nil on first check (unless you have some other persistence to know it's been set, which makes no sense). Can't believe the answer that was up so long was guaranteed crash. – Mike Sand Oct 20 '19 at 20:03
34

Swift 3/4/5 version using Date (type alias) instead of NSDate:

let yourDate = UserDefaults.standard.object(forKey: "yourKey") as? Date
UserDefaults.standard.set(yourDate, forKey: "yourKey")

Remember to use conditional cast operator as? to avoid crash if there is no date yet under "yourKey" in UserDefaults.

KlimczakM
  • 12,576
  • 11
  • 64
  • 83
3

In Swift 5,

You can do some easy encapsulation for better managing the code

struct UserSetting {

    static var shared = UserSetting()

    var practiceTime: Date?{
        get {
            return UserDefaults.standard.object(forKey: TimeScaler.start) as? Date
        }
        set(newVal){
            UserDefaults.standard.set(newVal, forKey: TimeScaler.start)
        }
    }

}



struct TimeScaler {

    static let start = "start"
}
dengST30
  • 3,643
  • 24
  • 25