Apa cara optimal menyimpan NSDate di NSUserDefaults?

174

Ada dua cara menyimpan NSDate di NSUserDefaults yang saya temui.

Opsi 1 - setObject: forKey:

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

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

Opsi 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 dan kontra

Pilihan 1

Ini tampaknya kompak dan logis. Namun, saya punya kekhawatiran tentang kesalahan ini karena bug Date Formatter .

pilihan 2

Ini tampaknya canggung. Saya juga tidak yakin keakuratannya - dalam satu tes yang saya lakukan, ketika saya mengambil kembali tanggal itu keluar oleh 48 detik, meskipun Apple Docs mengatakan bahwa NSTimeInterval memiliki "akurasi subsecond".

Persyaratan

Metode apa pun yang saya pilih, itu harus:

  1. Tepat dalam satu detik.

  2. Dapat dibaca dan dapat diandalkan.

Pertanyaan saya

Apakah ketidaktepatan dengan Opsi 2 karena saya melakukan sesuatu yang salah?

Manakah dari dua opsi ini yang akan Anda gunakan?

Apakah ada opsi lain yang tidak saya sadari?

Terima kasih!

John Gallagher
sumber

Jawaban:

380

Anda hal-hal rumit yang tidak perlu. Mengapa Anda mengubah tanggal menjadi interval waktu (kemudian interval waktu ke primitif yang berbeda)? Hanya[sharedDefaults setObject:theDate forKey:@"theDateKey"] dan selesai dengan itu. NSDate adalah salah satu "tipe utama" yang didukung oleh format PLIST (tanggal, angka, string, data, kamus, dan array), sehingga Anda dapat menyimpannya secara langsung.

Lihat dokumentasi untuk bukti.

Hanya menyimpan dan mengambil tanggal secara langsung dan menontonnya Melakukan Hal yang Benar (termasuk zona waktu, presisi, dll). Tidak ada formatter yang terlibat, seperti yang dikatakan orang lain.

Joshua Nozzi
sumber
8
Joshua, terima kasih atas jawaban Anda. Alasan saya mencoba pendekatan float berbelit-belit konyol itu hanya karena saya telah melihat pengembang hebat lain melakukannya dan saya pikir dia telah melakukannya untuk beberapa alasan bagus. Tentu saja tidak. Saya harus lebih percaya diri dengan insting saya sendiri, yaitu menggunakan setObject: forKey: dan telah melakukannya.
John Gallagher
7
Saya sangat kasar terhadap pemikiran tentang komplikasi yang tidak perlu - sifat yang baik untuk pengembang dan orang-orang yang biasanya malas. :-)
Joshua Nozzi
Kasus-kasus di mana pendekatan tersebut digunakan sebagian besar ketika NSUserDefaults digunakan sebagai implementasi penyimpanan preferensi pengguna untuk middleware umum ...
Coyote
@Coyote: Dalam hal ini masih diakses melalui NSUserDefaults atau diurai dari file daftar properti, sehingga akses atau parsing yang sama harus menghasilkan objek NSDate yang tepat, yang dapat dikonversi sesuai kebutuhan.
Joshua Nozzi
3
@ JohnGallagher [bilah sisi] Jangan salah mengartikan implementasi spesifik seseorang dengan yang buruk. Sentimen asli Anda "mengira ia telah melakukannya untuk beberapa alasan yang baik ... Jelas tidak" hanya bisa berlaku jika Anda memahami seluruh ruang lingkup persyaratan dev tersebut. Adalah lancang dan tertutup untuk secara buta menyebut pendekatannya sebagai "jelas bukan alasan yang baik untuk melakukannya dengan cara ini". Yang sedang berkata, ya saya akan setuju dengan pendekatan Yosua agar tetap sederhana jika Anda tidak memiliki alasan untuk melakukan sebaliknya.
dooleyo
14

Untuk opsi # 1, saya tidak percaya formatter tanggal terlibat. Mungkin di bawah tenda, tapi saya membayangkan itu tidak rusak. Tanggal disimpan dalam bentuk ISO 8601 .

Untuk opsi # 2, gunakan -setDouble:forKey:dan -doubleForKeybukan floatversi berbasis. Itu mungkin menjadi penyebab kesalahan presisi Anda.

John Calsbeek
sumber
Wow, John. Terima kasih atas jawaban Anda yang sangat cepat. Yang mana yang akan Anda gunakan secara pribadi?
John Gallagher
8
Gunakan tanggal secara langsung, bukan interval waktu. Saya ragu API dasar seperti itu rusak ketika begitu banyak aplikasi mengandalkannya.
John Calsbeek
Luar biasa. Itu adalah insting saya, tetapi saya telah melihat kode pihak ketiga oleh seorang dev yang disegani yang menggunakan metode float jadi saya pikir akan ada beberapa alasan bagus mengapa dia menggunakannya. Tentu saja tidak. Sekali lagi terima kasih atas jawaban Anda!
John Gallagher
1
Ada kemungkinan bahwa kode yang Anda lihat adalah dev yang tidak mengingat tipe mana yang dapat disimpan secara langsung dalam daftar properti.
John Calsbeek
2
Sebagai catatan - floats 32 bit hanya memiliki akurasi 24 bit, sehingga tahun 1970 hingga sekarang adalah 40 tahun, yaitu 40 * 365 * 86400 detik, dan (40 * 365 * 86 400) / (2 ** 24) = 75 detik kesalahan . Presisi ganda adalah interval DateTime, dan presisi RAW-nya sekarang lebih baik daripada sepersejuta detik.
Tom Andersen
5

Gunakan NSUserDefaults; tanggal disimpan dalam waktu Zulu, jadi tidak ada masalah zona waktu yang perlu dikhawatirkan. Simpan di zona waktu Anda, tarik keluar di zona waktu lain, Anda akan baik-baik saja, sistem menangani konversi (tidak ada formatter tanggal khawatir).

Ben Gottlieb
sumber
0

Jika Anda menyimpan tanggal kedaluwarsa dari Facebook Graph API, saya akan menggunakan * Opsi 2 * .

Opsi dua dapat dengan mudah dikonversi ke string (menggunakan stringWithFormat). Yang paling penting, ini berfungsi untuk API Grafik.

Plus, Anda tidak perlu khawatir tentang format tanggal Anda. Tidak berurusan dengan NSDateFormatter sepadan dengan kemungkinan kesalahan 48 detik.

Nate Symer
sumber