Search code examples
swiftuiios15

Initializing the Date Picker with Date Other Than Today


I need help with dates. How do you initialize the DatePicker with a stored date? Say, for example, that the user entered an entry with a date. He then determines the date is wrong and would like to change the date. But currently the DatePicker in this code will always default to today's date instead of the stored date.

The state parameter startDate can't be initialized with a stored date above the body. It appears that I need to set startDate in the body.

import SwiftUI
import Combine

struct GetDate: View {

    @ObservedObject var userData : UserData = UserData()
    @State private var startDate = Date()

    var body: some View {

        //let startDate = userData.startDate

        VStack (alignment: .leading) {

            Form {

                Text("startdate 1 = \(startDate)")


                // enter start date
                Section(header: Text("Enter Start Date")) {
                    HStack {
                        Image(systemName: "calendar.badge.clock")
                            .resizable()
                            .foregroundColor(Color(.systemRed))
                            .frame(width: 35, height: 35)

                        Spacer()

                        DatePicker("", selection: $startDate, in: ...Date(), displayedComponents: .date)
                            .datePickerStyle(CompactDatePickerStyle())
                    }
                }

                Button ( action: {
                    userData.saveDates(startDate: startDate)
                }) {

                    HStack {
                        Spacer()
                        Text("Save Dates?")
                        Spacer()
                    }
                }
            }
            .font(.body)
            .navigationBarTitle("Get Date", displayMode: .inline)
        }
    }
}


class UserData:  ObservableObject {

    @Published var startDate: Date = Date()  {
        didSet {
            UserDefaults.standard.set(startDate, forKey: "startDate")  // save
        }
    }


    init() {
        // save / retrieve trip dates
        if let sdate = UserDefaults.standard.object(forKey: "startDate") as? Date {
            startDate = sdate
            print("startDate 2 = \(startDate)")
        } else {
            UserDefaults.standard.set(Date(), forKey: "startDate")
        }
    }


    func saveDates(startDate: Date) -> () {

        self.startDate = startDate
        UserDefaults.standard.set(self.startDate, forKey: "startDate")

        print("startDate 3 = \(self.startDate)")
    }
}

Solution

  • Use @AppStorage property wrapper:

    struct GetDate: View {
      @AppStorage("startDate") var startDate = Date()
      @State private var selectedDate = Date()
      
      var body: some View {
        VStack (alignment: .leading) {
          Form {
            Text("startdate 1 = \(startDate)")
            Section(header: Text("Enter Start Date")) {
              HStack {
                Image(systemName: "calendar.badge.clock")
                  .resizable()
                  .foregroundColor(Color(.systemRed))
                  .frame(width: 35, height: 35)
                Spacer()
                DatePicker("", selection: $selectedDate, in: ...Date(), displayedComponents: .date)
                  .datePickerStyle(CompactDatePickerStyle())
              }
            }
            
            Button ( action: {
              startDate = selectedDate // save
            }) {
              HStack {
                Spacer()
                Text("Save Dates?")
                Spacer()
              }
            }
          }
          .font(.body)
          .navigationBarTitle("Get Date", displayMode: .inline)
        }
        .onAppear {
          selectedDate = startDate
        }
      }
    }
    
    // Support @AppStorage for `Date` type.
    extension Date: RawRepresentable {
      private static let formatter = ISO8601DateFormatter()
      
      public var rawValue: String {
        Date.formatter.string(from: self)
      }
      
      public init?(rawValue: String) {
        self = Date.formatter.date(from: rawValue) ?? Date()
      }
    }