Який оптимальний спосіб зберігання NSDate в NSUserDefaults?


174

Є два способи зберігання NSDate в NSUserDefaults, які я натрапив.

Варіант 1 - setObject: forKey:

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

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

Варіант 2 - часIntervalSince1970

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

Плюси і мінуси

Варіант 1

Це здається компактним та логічним. Однак я побоююся, що це піде не так через помилки Date Formatter .

Варіант 2

Це здається незграбним. Я також не впевнений у його точності - в одному тесті, який я робив, коли я повернув дату назад, вона вийшла на 48 секунд, незважаючи на те, що Apple Docs говорила, що NSTimeInterval має "нижню секунду точності".

Вимоги

Який би метод я не вибрав, він повинен бути:

  1. Точно протягом секунди.

  2. Зрозумілий і надійний.

Моє запитання

Чи неточність у варіанті 2, тому що я щось роблю не так?

Який із цих двох варіантів ви б використали?

Чи є інший варіант, про який я не знаю?

Дякую!

Відповіді:


380

Ви непотрібно ускладнюєте речі. Чому ви перетворюєте дату в часовий інтервал (тоді інтервал часу в інший примітив)? Просто [sharedDefaults setObject:theDate forKey:@"theDateKey"]і роби з цим. NSDate - це один з "основних типів", підтримуваний форматом PLIST (дати, числа, рядки, дані, словники та масиви), тому ви можете просто зберігати його безпосередньо.

Перегляньте документацію для підтвердження.

Просто зберігайте та отримуйте дату безпосередньо та дивіться, як це робиться правильно (включаючи часові пояси, точність тощо). Немає жодного форматера, як говорили інші.


8
Джошуа, дякую за вашу відповідь. Причиною, що я спробував дурно переплутаний підхід, був просто тому, що я бачив іншого великого розробника, який це робив, і думав, що він зробив це з якоїсь вагомої причини. Очевидно, що ні. Я повинен мати більше впевненості у власному інстинкті, який повинен був використовувати setObject: forKey: і зробив це з ним.
Джон Галлахер

7
Я відверто жорстокий до самої думки про непотрібне ускладнення - хороша риса для розробників і загалом лінивих людей. :-)
Джошуа Ноцці

Випадки, коли застосовується такий підхід, здебільшого, коли NSUserDefaults використовується як зберігання реалізації налаштувань користувача для загального середнього програмного забезпечення ...
Coyote

@Coyote: у такому випадку до нього все ще можна отримати доступ через NSUserDefaults або проаналізувати з файла списку властивостей, тому той самий доступ або синтаксичний аналіз повинен отримати належний об'єкт NSDate, який можна перетворити за необхідності.
Джошуа Ноцці

3
@JohnGallagher [бічна панель] Не помиляйтеся на чиюсь конкретну реалізацію для поганої. Ваші первісні настрої "думали, що він це зробив з якоїсь поважної причини ... Очевидно, що не" могли бути дійсними лише тоді, коли ви розумієте всю сферу вимог зазначеного диявола. Дуже нахабно і уважно сліпо позначати свій підхід як "очевидно, що немає вагомих причин робити це таким чином". Коли це було сказано, так, я б погодився з підходом Джошуа, щоб зробити це просто, якщо у вас немає підстав робити інше.
dooleyo

14

У варіанті №1 я не вірю, що формат дати має участь. Можливо, під капотом, але я думаю, що це не зламано. Дата зберігається у формі ISO 8601 .

Для варіанту №2 використовуйте -setDouble:forKey:та -doubleForKeyзамість floatверсій-баз. Це може бути причиною ваших помилок точності.


Нічого собі, Джон. Дякую за дуже швидку відповідь. Яким би ви особисто користувалися?
Джон Галлахер

8
Використовуйте дату безпосередньо, а не інтервал часу. Я сумніваюся, що такий базовий API зламається, коли на нього покладається так багато додатків.
Джон Калсбек

Відмінно. Це був мій інстинкт, але я бачив код стороннього поважного розробника, який використовував метод float, тож я подумав, що буде якийсь вагомий привід, що він його використав. Очевидно, що ні. Ще раз дякую за вашу відповідь!
Джон Галлахер

1
Можливо, що той код, який ви бачили, був розробником, який не пам’ятав, які типи можна зберігати безпосередньо у списку властивостей.
Джон Калсбек

2
Для запису - 32-бітові поплавці мають лише 24 біти для точності, тому 1970-го до цього часу 40 років, що становить 40 * 365 * 86400 секунд, і (40 * 365 * 86 400) / (2 ** 24) = 75 секундних помилок . Подвійна точність - це інтервал DateTime, а його точність RAW тепер краща за мільйонну частину секунди.
Том Андерсен

5

Використовувати NSUserDefaults; Дати зберігаються в зулуський час, тому проблем із часовим поясом не потрібно хвилювати. Зберігайте його у своєму часовому поясі, витягайте його в інший часовий пояс, ви будете добре, система обробляє перетворення (жодного форматера дати не турбувати).


0

Якщо ви зберігаєте дату закінчення терміну дії від API Graph Graph, я б застосував * Варіант 2 * .

Варіант другий може бути легко перетворений у рядок (використовуючи stringWithFormat). Найголовніше, що він працює для Graph API.

Крім того, вам не доведеться турбуватися про формат своєї дати. Не мати справу з NSDateFormatter, варто можливість помилки 48 секунд.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.