Was ist die optimale Methode zum Speichern eines NSDate in NSUserDefaults?

174

Es gibt zwei Möglichkeiten, ein NSDate in NSUserDefaults zu speichern, auf die ich gestoßen bin.

Option 1 - setObject: forKey:

// Set
NSDate *myDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:myDate forKey:@"myDateKey"];

// Get
NSDate *myDate = (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:@"myDateKey"];

Option 2 - timeIntervalSince1970

// Set
NSDate *myDate = [NSDate date];
NSTimeInterval myDateTimeInterval = [myDate timeIntervalSince1970];
[[NSUserDefaults standardUserDefaults] setFloat:myDateTimeInterval forKey:@"myDateKey"];

// Get
NSTimeInterval myDateTimeInterval = [[NSUserDefaults standardUserDefaults] floatForKey:@"myDateKey"];
NSDate *myDate = [NSDate dateWithTimeIntervalSince1970:myDateTimeInterval];

Vor-und Nachteile

Option 1

Dies scheint kompakt und logisch zu sein. Ich habe jedoch Bedenken, dass dies aufgrund von Date Formatter-Fehlern schief geht .

Option 2

Das scheint ungeschickt zu sein. Ich bin mir auch nicht sicher, wie genau das ist - in einem Test, den ich durchgeführt habe, war das Datum, als ich es zurückerhielt, um 48 Sekunden abgelaufen, obwohl die Apple Docs sagten, dass NSTimeInterval eine "Genauigkeit von weniger als einer Sekunde" hat.

Bedarf

Welche Methode ich auch wähle, es muss sein:

  1. Präzise auf eine Sekunde.

  2. Lesbar und zuverlässig.

Meine Frage

Ist die Ungenauigkeit mit Option 2, weil ich etwas falsch mache?

Welche dieser beiden Optionen würden Sie verwenden?

Gibt es eine andere Option, die mir nicht bekannt ist?

Vielen Dank!

John Gallagher
quelle

Antworten:

380

Sie komplizieren die Dinge unnötig. Warum konvertieren Sie das Datum in ein Zeitintervall (dann das Zeitintervall in ein anderes Grundelement)? Einfach [sharedDefaults setObject:theDate forKey:@"theDateKey"]und fertig damit. NSDate ist einer der "Haupttypen", die vom PLIST-Format unterstützt werden (Datumsangaben, Zahlen, Zeichenfolgen, Daten, Wörterbücher und Arrays), sodass Sie es einfach direkt speichern können.

Beweise finden Sie in der Dokumentation .

Speichern und rufen Sie das Datum einfach direkt ab und sehen Sie zu, wie es das Richtige tut (einschließlich Zeitzonen, Präzision usw.). Es ist kein Formatierer beteiligt, wie andere gesagt haben.

Joshua Nozzi
quelle
8
Joshua, danke für deine Antwort. Der Grund, warum ich den albernen, verschlungenen Float-Ansatz ausprobiert habe, war einfach, dass ich einen anderen großartigen Entwickler gesehen hatte und dachte, er hätte es aus irgendeinem guten Grund getan. Offensichtlich nicht. Ich sollte mehr Vertrauen in meinen eigenen Instinkt haben, der setObject: forKey: verwenden sollte, und damit fertig sein.
John Gallagher
7
Ich bin geradezu gewalttätig gegenüber dem Gedanken an unnötige Komplikationen - eine gute Eigenschaft für Entwickler und allgemein faule Leute. :-)
Joshua Nozzi
Die Fälle, in denen ein solcher Ansatz verwendet wird, sind meistens, wenn NSUserDefaults als Speicherimplementierung von Benutzereinstellungen für eine generische Middleware verwendet wird ...
Coyote
@Coyote: In diesem Fall wird weiterhin über NSUserDefaults darauf zugegriffen oder aus einer Eigenschaftslistendatei analysiert. Daher sollte derselbe Zugriff oder dieselbe Analyse ein ordnungsgemäßes NSDate-Objekt ergeben, das bei Bedarf konvertiert werden kann.
Joshua Nozzi
3
@ JohnGallagher [Seitenleiste] Verwechseln Sie die spezifische Implementierung einer Person nicht mit einer schlechten. Ihr ursprüngliches Gefühl "dachte, er hätte es aus einem guten Grund getan ... offensichtlich nicht" könnte nur gültig sein, wenn Sie den gesamten Umfang der Anforderungen des Entwicklers verstanden haben. Es ist anmaßend und aufgeschlossen, seinen Ansatz blind als "offensichtlich keinen guten Grund, dies so zu tun" zu bezeichnen. Davon abgesehen würde ich Joshuas Ansatz zustimmen, es einfach zu halten, wenn Sie keinen Grund haben, etwas anderes zu tun.
Dooleyo
14

Für Option 1 glaube ich nicht, dass ein Datumsformatierer beteiligt ist. Möglicherweise unter der Haube, aber ich stelle mir vor, es ist nicht kaputt. Das Datum wird in ISO 8601- Form gespeichert .

Verwenden Sie für Option 2 -setDouble:forKey:und -doubleForKeyanstelle der floatbasierten Versionen. Dies könnte die Ursache für Ihre Präzisionsfehler sein.

John Calsbeek
quelle
Wow, John. Vielen Dank für Ihre sehr schnelle Antwort. Welches würden Sie persönlich verwenden?
John Gallagher
8
Verwenden Sie das Datum direkt, nicht das Zeitintervall. Ich bezweifle, dass eine so grundlegende API kaputt ist, wenn so viele Apps darauf angewiesen sind.
John Calsbeek
Ausgezeichnet. Das war mein Instinkt, aber ich hatte Code von Drittanbietern von einem angesehenen Entwickler gesehen, der die Float-Methode verwendete, also dachte ich, dass es einen guten Grund geben würde, warum er ihn verwendet hatte. Offensichtlich nicht. Nochmals vielen Dank für Ihre Antwort!
John Gallagher
1
Es ist möglich, dass der Code, den Sie gesehen haben, der Entwickler war, der sich nicht daran erinnert, welche Typen direkt in einer Eigenschaftsliste gespeichert werden können.
John Calsbeek
2
Für die Aufzeichnung - 32-Bit-Floats haben nur 24 Bit für die Genauigkeit, so dass 1970 bis jetzt 40 Jahre sind, was 40 * 365 * 86400 Sekunden und (40 * 365 * 86 400) / (2 ** 24) = 75 Sekunden Fehler ist . Doppelte Genauigkeit ist das, was ein DateTime-Intervall ist, und seine RAW-Genauigkeit ist jetzt besser als eine Millionstel Sekunde.
Tom Andersen
5

Verwenden Sie NSUserDefaults. Daten werden in Zulu-Zeit gespeichert, sodass Sie sich keine Sorgen um Zeitzonen machen müssen. Speichern Sie es in Ihrer Zeitzone, ziehen Sie es in einer anderen Zeitzone heraus, es wird Ihnen gut gehen, das System übernimmt die Konvertierung (kein Datumsformatierer, über den Sie sich Sorgen machen müssen).

Ben Gottlieb
quelle
0

Wenn Sie das Ablaufdatum über die Facebook Graph-API speichern, würde ich * Option 2 * verwenden .

Option zwei kann einfach in eine Zeichenfolge konvertiert werden (mithilfe von stringWithFormat). Am wichtigsten ist, dass es für die Graph-API funktioniert.

Außerdem müssen Sie sich keine Gedanken über das Format Ihres Datums machen. Wenn Sie sich nicht mit NSDateFormatter befassen, kann ein Fehler von 48 Sekunden auftreten.

Nate Symer
quelle