Qual è il modo ottimale di archiviare un NSDate in NSUserDefaults?


174

Esistono due modi per memorizzare un NSDate in NSUserDefaults che ho riscontrato.

Opzione 1 - setObject: forKey:

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

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

Opzione 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];

Pro e contro

opzione 1

Questo sembra essere compatto e logico. Tuttavia, mi preoccupo che ciò vada storto a causa di bug di Date Formatter .

opzione 2

Questo sembra essere goffo. Inoltre, non sono sicuro della precisione di ciò - in un test che ho fatto, quando ho recuperato la data precedente, era uscito di 48 secondi, nonostante i documenti di Apple affermassero che NSTimeInterval ha "una precisione inferiore al secondo".

Requisiti

Qualunque metodo scelga, deve essere:

  1. Preciso entro un secondo.

  2. Leggibile e affidabile.

La mia domanda

L'inesattezza con l'Opzione 2 è perché sto facendo qualcosa di sbagliato?

Quale di queste due opzioni useresti?

Esiste un'altra opzione di cui non sono a conoscenza?

Grazie!

Risposte:


380

Stai complicando inutilmente le cose. Perché stai convertendo la data in un intervallo di tempo (quindi l'intervallo di tempo in una primitiva diversa)? Basta [sharedDefaults setObject:theDate forKey:@"theDateKey"]e aver finito. NSDate è uno dei "tipi principali" supportati dal formato PLIST (date, numeri, stringhe, dati, dizionari e array), quindi puoi semplicemente memorizzarlo direttamente.

Vedere la documentazione per la prova.

Basta archiviare e recuperare direttamente la data e guardarla Fare la cosa giusta (inclusi fusi orari, precisione, ecc.). Non c'è nessun formatter coinvolto, come altri hanno già detto.


8
Giosuè, grazie per la tua risposta. Il motivo per cui ho provato l'approccio fluttuante e sciocco è semplicemente perché avevo visto un altro grande sviluppatore farlo e ho pensato che lo avesse fatto per qualche buona ragione. Ovviamente no. Dovrei avere più fiducia nel mio istinto, che era di usare setObject: forKey: e averlo fatto.
John Gallagher,

7
Sono assolutamente violento nei confronti del pensiero stesso di complicazioni inutili: un buon tratto per sviluppatori e persone generalmente pigre. :-)
Joshua Nozzi

I casi in cui viene utilizzato tale approccio sono principalmente quando NSUserDefaults viene utilizzato come implementazione di archiviazione delle preferenze dell'utente per un middleware generico ...
Coyote

@Coyote: nel qual caso viene ancora effettuato l'accesso tramite NSUserDefaults o analizzato da un file dell'elenco delle proprietà, quindi lo stesso accesso o analisi dovrebbe produrre un oggetto NSDate corretto, che può essere convertito secondo necessità.
Joshua Nozzi,

3
@JohnGallagher [sidebar] Non confondere l'implementazione specifica di qualcuno con una povera. Il tuo sentimento originale "pensava di averlo fatto per qualche buona ragione ... Ovviamente no" potrebbe essere valido solo se avessi compreso l'intero ambito dei requisiti di detto sviluppatore. È presuntuoso e risoluto etichettare alla cieca il suo approccio come "ovviamente nessuna buona ragione per farlo in questo modo". Detto questo, sì, sarei d'accordo con l'approccio di Joshua per mantenerlo semplice se non avessi motivo di fare diversamente.
dooleyo,

14

Per l'opzione n. 1, non credo sia coinvolto un formattatore di date. Forse sotto il cofano, ma immagino che non sia rotto. La data è memorizzata nel formato ISO 8601 .

Per l'opzione n. 2, utilizzare -setDouble:forKey:e -doubleForKeyanziché le floatversioni basate su. Questa potrebbe essere la causa dei tuoi errori di precisione.


Wow, John. Grazie per la tua risposta molto rapida. Quale useresti personalmente?
John Gallagher,

8
Utilizza direttamente la data, non l'intervallo di tempo. Dubito che un'API di base di questo tipo venga interrotta quando così tante app si affidano ad essa.
John Calsbeek,

Eccellente. Quello era il mio istinto, ma avevo visto il codice di terze parti da un dev rispettato che utilizzava il metodo float, quindi ho pensato che ci sarebbe stata qualche buona ragione per averlo usato. Ovviamente no. Grazie ancora per la tua risposta!
John Gallagher,

1
È possibile che quel codice che hai visto fosse lo sviluppatore che non ricordava quali tipi possono essere memorizzati direttamente in un elenco di proprietà.
John Calsbeek,

2
Per la cronaca: i float a 32 bit hanno solo 24 bit per la precisione, quindi dal 1970 ad oggi sono 40 anni, ovvero 40 * 365 * 86400 secondi e (40 * 365 * 86 400) / (2 ** 24) = errore di 75 secondi . La doppia precisione è un intervallo di DateTime e la sua precisione RAW è ora migliore di un milionesimo di secondo.
Tom Andersen,

5

Usa NSUserDefaults; le date sono memorizzate nell'ora Zulu, quindi non ci sono problemi di fuso orario di cui preoccuparsi. Memorizzalo nel tuo fuso orario, estrailo in un altro fuso orario, andrà tutto bene, il sistema gestisce la conversione (nessun formatter data di cui preoccuparsi).


0

Se stai salvando la data di scadenza dall'API Graph di Facebook, utilizzerei * Opzione 2 * .

L'opzione due può essere facilmente convertita in una stringa (usando stringWithFormat). Ancora più importante, funziona per l'API Graph.

Inoltre, non devi preoccuparti del formato della tua data. Non trattare con NSDateFormatter vale la possibilità di un errore di 48 secondi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.