Bagaimana cara menyimpan data lokal di aplikasi Swift?

149

Saat ini saya sedang mengerjakan aplikasi iOS yang dikembangkan di Swift dan saya perlu menyimpan beberapa konten yang dibuat pengguna di perangkat, tetapi sepertinya saya tidak bisa menemukan cara sederhana dan cepat untuk menyimpan / menerima konten pengguna di perangkat.

Bisakah seseorang menjelaskan cara menyimpan dan mengakses penyimpanan lokal?

Idenya adalah untuk menyimpan data ketika pengguna menjalankan suatu tindakan dan menerimanya saat aplikasi dimulai.

Nicklas Ridewing
sumber
Hai dan selamat datang, data apa yang Anda simpan? Bisakah Anda memberikan kode apa saja untuk memberikan contoh apa yang Anda cari? Terima kasih.
Wez
1
Data yang saya perlu simpan pada dasarnya hanya data string. Jadi untuk membuatnya sangat sederhana, saya perlu menyimpan dua nilai String yang dapat saya terima jika pengguna me-restart aplikasi.
Nicklas Ridewing
2
Anda dapat menggunakan NSUserDefaults. Berikut adalah informasi yang Anda butuhkan codingexplorer.com/nsuserdefaults-a-swift-introduction
bpolat

Jawaban:

197

Solusi paling sederhana jika Anda hanya menyimpan dua string adalah NSUserDefaults, di Swift 3 kelas ini telah diubah namanya menjadi adil UserDefaults.

Yang terbaik adalah menyimpan kunci Anda di suatu tempat secara global sehingga Anda dapat menggunakannya kembali di tempat lain dalam kode Anda.

struct defaultsKeys {
    static let keyOne = "firstStringKey"
    static let keyTwo = "secondStringKey"
}

Swift 3.0, 4.0 & 5.0

// Setting

let defaults = UserDefaults.standard
defaults.set("Some String Value", forKey: defaultsKeys.keyOne)
defaults.set("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = UserDefaults.standard
if let stringOne = defaults.string(forKey: defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.string(forKey: defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Swift 2.0

// Setting

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Some String Value", forKey: defaultsKeys.keyOne)
defaults.setObject("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = NSUserDefaults.standardUserDefaults()
if let stringOne = defaults.stringForKey(defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.stringForKey(defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Untuk hal yang lebih serius daripada konfigurasi minor, flag atau string dasar, Anda harus menggunakan semacam toko persisten - Opsi yang populer saat ini adalah Realm tetapi Anda juga dapat menggunakan SQLite atau CoreData milik Apple sendiri .

Wez
sumber
7
Contoh yang bagus. Ini mungkin harus menjadi enum bukan struct.
pan-and-scan
3
Itu implementasi enum yang aneh, jika Anda hanya memiliki konstanta statis, mungkin juga sebuah struct.
Craig Grummitt
1
Kode ini salah. Jangan gunakan metode KVC setValue(_:forKey:)untuk menyimpan data ke UserDefaults. Gunakan UserDefaultsmetode yang disediakan set(_:forKey:)(dalam Swift 3).
rmaddy
Saya memperbarui kode Swift 3. Saya tidak tahu apa sintaks Swift 2 seharusnya.
rmaddy
@rmaddy tidak apa-apa.
Wez
57

Mereka Mengatakan Menggunakan NSUserDefaults

Ketika saya menerapkan penyimpanan data jangka panjang (setelah aplikasi tutup) untuk pertama kalinya, semua yang saya baca online mengarahkan saya ke NSUserDefaults. Namun, saya ingin menyimpan kamus dan, meskipun mungkin, itu terbukti menyebalkan. Saya menghabiskan berjam-jam mencoba untuk mendapatkan kesalahan tipe untuk pergi.

Fungsi NSUserDefaults Juga Terbatas

Bacaan lebih lanjut mengungkapkan bagaimana membaca / menulis NSUserDefaults benar-benar memaksa aplikasi untuk membaca / menulis semuanya atau tidak sama sekali, sekaligus, sehingga tidak efisien. Kemudian saya belajar bahwa mengambil array tidak langsung. Saya menyadari bahwa jika Anda menyimpan lebih dari beberapa string atau boolean, NSUserDefaults benar-benar tidak ideal.

Ini juga tidak dapat diskalakan. Jika Anda mempelajari cara membuat kode, pelajari cara yang dapat diskalakan. Hanya gunakan NSUserDefaults untuk menyimpan string atau boolean sederhana yang terkait dengan preferensi. Menyimpan array dan data lainnya menggunakan Core Data, tidak sesulit yang mereka katakan. Mulailah dari yang kecil.

Pembaruan: Juga, jika Anda menambahkan dukungan Apple Watch, ada pertimbangan potensial lain. NSUserDefaults aplikasi Anda sekarang secara otomatis dikirim ke Watch Extension.

Menggunakan Data Inti

Jadi saya mengabaikan peringatan tentang Data Inti sebagai solusi yang lebih sulit dan mulai membaca. Dalam tiga jam saya berhasil. Saya meminta array tabel saya disimpan di Core Data dan memuat ulang data setelah membuka aplikasi kembali! Kode tutorialnya cukup mudah untuk diadaptasi dan saya bisa membuatnya menyimpan judul dan array detail hanya dengan sedikit eksperimen tambahan.

Jadi bagi siapa pun yang membaca posting ini yang berjuang dengan masalah tipe NSUserDefault atau yang kebutuhannya lebih dari menyimpan string, pertimbangkan menghabiskan satu atau dua jam bermain dengan data inti.

Inilah tutorial yang saya baca:

http://www.raywenderlich.com/85578/first-core-data-app-using-swift

Jika Anda tidak memeriksa "Data Inti"

Jika Anda tidak memeriksa "Data Inti" saat membuat aplikasi, Anda dapat menambahkannya setelah itu dan hanya membutuhkan waktu lima menit:

http://craig24.com/2014/12/how-to-add-core-data-to-an-existing-swift-project-in-xcode/

http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-existing-swift-project

Cara Menghapus dari Daftar Data Inti

Hapus Data dari Coredata Swift

Dave G
sumber
6
Ada jalan tengah menyimpan data Anda ke file .plist di suatu tempat di direktori Documents atau di tempat lain di direktori sandbox aplikasi.
Nicolas Miari
Saya seorang pemula, jadi jawab pertanyaan ini dengan sebutir garam, tetapi apakah jalan tengah itu? NSUserDefaults bisa dibilang adalah file p.list, jadi (berdasarkan apa yang saya baca) menyimpan ke file p.list dalam direktori dokumen agak sama dengan menggunakan NSUserDefaults. Alasan saya tidak menggunakan metode itu adalah karena menyimpan array ke p.list terdengar seperti melibatkan langkah-langkah tambahan, seperti mengonversinya ke tipe lain dan kemudian, ketika mengembalikan nilai, diperlukan penugasan ulang nilai setelah membacanya. dari daftar p. Sekali lagi, semata-mata berdasarkan bacaan saya selama beberapa hari terakhir.
Dave G
Nah, menyimpan array ke file .plist cukup mudah (semua objek dalam hierarki adalah Array, String, Kamus, atau Angka (tanpa kelas khusus).
Nicolas Miari
Setuju, membaca file adalah semua atau tidak sama sekali, tetapi Anda dapat membagi data Anda menjadi file terpisah tergantung pada strukturnya. Dan CoreData memiliki kurva belajar yang signifikan, setidaknya saat terakhir saya memeriksanya.
Nicolas Miari
3
Saya akan mengatakan: gunakan NSUserDefaults untuk menyimpan preferensi (itu artinya namanya), Keychain untuk menyimpan data persisten dan / atau sensitif, skema kustom Anda dari file .plist untuk data yang dihasilkan aplikasi yang sangat dasar , dan CoreData untuk hal-hal yang lebih berat .
Nicolas Miari
11

Oke, terima kasih kepada @bploat dan tautannya ke http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/

Saya telah menemukan bahwa jawabannya cukup sederhana untuk beberapa penyimpanan string dasar.

let defaults = NSUserDefaults.standardUserDefaults()

// Store
defaults.setObject("theGreatestName", forKey: "username")

// Receive
if let name = defaults.stringForKey("username")
{
    print(name)
    // Will output "theGreatestName"
}

Saya telah meringkasnya di sini http://ridewing.se/blog/save-local-data-in-swift/

Nicklas Ridewing
sumber
9

Menggunakan NSCoding dan NSKeyedArchiver adalah pilihan bagus lainnya untuk data yang terlalu rumit NSUserDefaults, tetapi untuk CoreData akan membutuhkan banyak. Ini juga memberi Anda kesempatan untuk mengelola struktur file secara lebih eksplisit, yang sangat bagus jika Anda ingin menggunakan enkripsi.

Patrick Lynch
sumber
7

Untuk Swift 4.0, ini menjadi lebih mudah:

let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")
Teknologi Levinson
sumber
6

Swift 3.0

Setter: Penyimpanan Lokal

let authtoken = "12345"
    // Userdefaults helps to store session data locally 
 let defaults = UserDefaults.standard                                           
defaults.set(authtoken, forKey: "authtoken")

 defaults.synchronize()

Getter: Penyimpanan Lokal

 if UserDefaults.standard.string(forKey: "authtoken") != nil {

//perform your task on success }
Ravindra Shekhawat
sumber
2
Anda tidak boleh menyimpan sesuatu seperti authtoken di UserDefaults..Silakan gunakan Keychain untuk ini
BilalReffas
5

Untuk Swift 3

UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")
Arun Yokesh
sumber
Jangan gunakan metode KVC untuk menyimpan data.
rmaddy
4

Untuk seseorang yang tidak suka menangani UserDefaults karena beberapa alasan, ada opsi lain - NSKeyedArchiver & NSKeyedUnarchiver. Ini membantu menyimpan objek ke dalam file menggunakan pengarsipan, dan memuat file yang diarsipkan ke objek asli.

// To archive object,
let mutableData: NSMutableData = NSMutableData()
let archiver: NSKeyedArchiver = NSKeyedArchiver(forWritingWith: mutableData)
archiver.encode(object, forKey: key)
archiver.finishEncoding()
return mutableData.write(toFile: path, atomically: true)

// To unarchive objects,
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let object = unarchiver.decodeObject(forKey: key)
}

Saya telah menulis sebuah utilitas sederhana untuk menyimpan / memuat objek di penyimpanan lokal, menggunakan kode contoh di atas. Anda mungkin ingin melihat ini. https://github.com/DragonCherry/LocalStorage

DragonCherry
sumber
4

Swift 5+

Tidak ada jawaban yang benar-benar membahas secara terperinci standar bawaan pada kemampuan penyimpanan lokal. Itu bisa melakukan jauh lebih dari sekadar string.

Anda memiliki opsi berikut langsung dari dokumentasi apple untuk mendapatkan data dari default.

func object(forKey: String) -> Any?
//Returns the object associated with the specified key.

func url(forKey: String) -> URL?
//Returns the URL associated with the specified key.

func array(forKey: String) -> [Any]?
//Returns the array associated with the specified key.

func dictionary(forKey: String) -> [String : Any]?
//Returns the dictionary object associated with the specified key.

func string(forKey: String) -> String?
//Returns the string associated with the specified key.

func stringArray(forKey: String) -> [String]?
//Returns the array of strings associated with the specified key.

func data(forKey: String) -> Data?
//Returns the data object associated with the specified key.

func bool(forKey: String) -> Bool
//Returns the Boolean value associated with the specified key.

func integer(forKey: String) -> Int
//Returns the integer value associated with the specified key.

func float(forKey: String) -> Float
//Returns the float value associated with the specified key.

func double(forKey: String) -> Double
//Returns the double value associated with the specified key.

func dictionaryRepresentation() -> [String : Any]
//Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.

Berikut adalah opsi untuk 'pengaturan'

func set(Any?, forKey: String)
//Sets the value of the specified default key.

func set(Float, forKey: String)
//Sets the value of the specified default key to the specified float value.

func set(Double, forKey: String)
//Sets the value of the specified default key to the double value.

func set(Int, forKey: String)
//Sets the value of the specified default key to the specified integer value.

func set(Bool, forKey: String)
//Sets the value of the specified default key to the specified Boolean value.

func set(URL?, forKey: String)
//Sets the value of the specified default key to the specified URL.

Jika menyimpan hal-hal seperti preferensi dan bukan kumpulan data besar ini adalah opsi yang sangat baik.

Contoh ganda :

Pengaturan:

let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")

Mendapatkan:

let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")

Yang menarik dari salah satu getter adalah dictionaryRepresentation , pengambil berguna ini akan mengambil semua tipe data Anda apa pun mereka dan memasukkannya ke dalam kamus yang bagus yang dapat Anda akses dengan nama stringnya dan memberikan tipe data yang sesuai saat Anda meminta kembali karena itu tipe 'apa saja' .

Anda dapat menyimpan kelas dan objek Anda sendiri juga menggunakan func set(Any?, forKey: String)danfunc object(forKey: String) -> Any? setter dan pengambil sesuai.

Semoga ini menjelaskan lebih banyak kekuatan kelas UserDefaults untuk menyimpan data lokal.

Dengan catatan berapa banyak yang harus Anda simpan dan seberapa sering, Hardy_Germany memberikan jawaban yang bagus tentang hal itu pada posting ini , berikut adalah kutipan darinya

Seperti yang telah disebutkan: Saya tidak mengetahui adanya batasan SIZE (kecuali memori fisik) untuk menyimpan data dalam .plist (mis. UserDefaults). Jadi ini bukan pertanyaan BAGAIMANA BANYAK.

Pertanyaan yang sebenarnya seharusnya adalah BAGAIMANA ANDA SERING menulis nilai yang baru / berubah ... Dan ini terkait dengan pengurasan baterai yang disebabkan oleh penulisan ini.

IOS tidak memiliki kesempatan untuk menghindari tulisan fisik ke "disk" jika ada satu nilai yang berubah, hanya untuk menjaga integritas data. Mengenai UserDefaults ini menyebabkan seluruh file ditulis ulang ke disk.

Ini memperkuat "disk" dan membuatnya tetap menyala untuk waktu yang lebih lama dan mencegah IOS masuk ke kondisi daya rendah.

Hal lain yang perlu diperhatikan sebagaimana disebutkan oleh pengguna Mohammad Reza Farahani dari postingan ini adalah sifat asinkron dan sinkron dari userDefaults.

Ketika Anda menetapkan nilai default, itu berubah secara sinkron dalam proses Anda, dan secara tidak sinkron ke penyimpanan persisten dan proses lainnya.

Misalnya, jika Anda menyimpan dan menutup program dengan cepat, Anda mungkin memperhatikan bahwa itu tidak menyimpan hasil, ini karena program itu tetap asinkron. Anda mungkin tidak memperhatikan hal ini setiap saat, jadi jika Anda berencana menabung sebelum keluar dari program, Anda mungkin ingin memperhitungkannya dengan memberikan waktu untuk menyelesaikannya.

Mungkin ada yang punya solusi bagus untuk ini yang bisa mereka bagikan di komentar?

Joseph Astrahan
sumber
0

NsUserDefaults hanya menyimpan ukuran variabel kecil. Jika Anda ingin menyimpan banyak objek, Anda dapat menggunakan CoreData sebagai solusi asli, atau saya membuat perpustakaan yang membantu Anda menyimpan objek semudah fungsi .save (). Ini didasarkan pada SQLite.

SundeedQLite

Lihatlah dan ceritakan komentar Anda

sandid Anda
sumber