NSUserDefaults - Cara mengetahui apakah ada kunci

208

Saya sedang mengerjakan aplikasi iPhone kecil, dan saya gunakan NSUserDefaultssebagai ketekunan data saya. Itu hanya harus melacak beberapa hal, seperti beberapa nama dan beberapa angka jadi saya pikir saya mungkin juga tetap sederhana.

Saya menemukan halaman ini untuk referensi, tetapi saya rasa itu tidak bisa menjawab pertanyaan saya. Pada dasarnya, saya ingin dapat memeriksa apakah suatu nilai (atau kunci) sudah ada di NSUserDefaultsdan kemudian melakukan sesuatu yang sesuai.

Beberapa contoh: Aplikasi dijalankan, jika ini pertama kali dijalankan akan menampilkan peringatan yang mengatakan selamat datang. Untuk mengetahui apakah ini pertama kali dibuka, bacalah UserDefaultsdan periksa.

Contoh 2: Bunyinya, "Halo [Nama]", di mana Nama adalah sesuatu yang Anda masukkan. Jika Anda telah membuka aplikasi dan tidak ada nama, itu seharusnya mengatakan "Hello World." Saya perlu memeriksa apakah Anda sudah memasukkan nama dan bertindak sesuai. Nama akan disimpan di NSUserDefaults.

Ada bantuan di sini? Saya sangat menghargainya!

Ethan Mick
sumber

Jawaban:

382

objectForKey:akan kembali niljika tidak ada.

jspcal
sumber
1
Saya tidak berpikir Anda dapat menyimpan tipe data primitif di NSUserDefaults.
kender
12
Dokumen Apple mengatakan bahwa "Jika nilai boolean dikaitkan dengan defaultName di default pengguna, nilai itu dikembalikan. Jika tidak, NO dikembalikan." Saya tidak berpikir jawaban di atas adalah benar untuk BOOL, Anda tidak dapat menentukan apakah itu didefinisikan TIDAK atau tidak ada. Saya pikir Anda harus menggunakan – dictionaryRepresentationdan memeriksa kuncinya.
zekel
40
@zekel Alih-alih menebak, saya menguji ini (pada iOS 5.1.1), dan pasti mendeteksi apakah BOOL hadir atau tidak, terlepas dari nilai BOOL tersebut. "objectForKey" mengembalikan nol ketika BOOL tidak hadir karena belum pernah ditetapkan.
DataGraham
8
Jika Anda memiliki BOOL dan mengujinya dengan boolForKey, maka @zekel benar, Anda mendapatkan YA atau TIDAK. Jika Anda mengujinya dengan objectForKey (seperti yang disarankan jawabannya) Anda mendapatkan nihil jika kunci tidak disetel.
Giuseppe Garassino
2
Ini tidak lagi berfungsi setidaknya pada iOS 6.1 Simulator. objectForKey mengembalikan nilai yang sama jika tidak ada dan jika hadir dengan BULAN NO. Solusi i.jameelkhan berhasil
lschult2
98

Seperti disebutkan di atas, ia tidak akan berfungsi untuk tipe primitif di mana 0 / NO bisa menjadi nilai yang valid. Saya menggunakan kode ini.

NSUserDefaults *defaults= [NSUserDefaults standardUserDefaults];
if([[[defaults dictionaryRepresentation] allKeys] containsObject:@"mykey"]){

    NSLog(@"mykey found");
}
i.jameelkhan
sumber
Ini menyelamatkan saya. Terima kasih!
BalestraPatrick
Ini adalah jawaban yang benar ketika berhadapan dengan primitif suka BOOL. Ini akan secara akurat membedakan antara NOdan tidak diatur, tidak seperti objectForKey:.
devios1
@ devios1 - Jika kunci tidak ada, objectForKey:akan kembali nilterlepas dari niat programmer untuk akhirnya menyimpan Boolatau tipe data lainnya. Ketika primitif hadir, objectForKey:tidak kembali nilbahkan jika kunci dikaitkan dengan nilai primitif.
Ted Hopp
Ini adalah jawaban yang benar: jelas, jawaban yang diterima salah karena objectForKey membingungkan 0 dengan nol, sehingga tidak bisa bekerja. Diuji berhasil dari iOS 4.3 hingga 10.2.1
Chrysotribax
Saya tahu ini sudah tua, tetapi baru saja memerlukan informasi ini, saya perlu menunjukkan bahwa referensi 'berisiObject:' berarti hanya itu: objek. BUKAN kuncinya. TKI, di file header Anda jika Anda mendefinisikan: #define kMyKey @ "myKey" the 'berisiObject' tidak mencari 'kMyKey', ia mencari 'myKey'. Menggunakan 'kMyKey' akan selalu mengembalikan 'TIDAK.'
Bill Norman
55

The objectForKey:Metode akan kembali niljika nilai tidak ada. Berikut adalah tes IF / THEN sederhana yang akan memberi tahu Anda jika nilainya nol:

if([[NSUserDefaults standardUserDefaults] objectForKey:@"YOUR_KEY"] != nil) {
    ...
}
mirap
sumber
6

" objectForKey akan mengembalikan nihil jika tidak ada. " Ia juga akan mengembalikan nihil jika memang ada dan itu adalah bilangan bulat atau boolean dengan nilai nol (yaitu SALAH atau TIDAK untuk boolean).

Saya sudah menguji ini di simulator untuk 5.1 dan 6.1. Ini berarti bahwa Anda tidak dapat benar-benar menguji apakah bilangan bulat atau boolean telah ditetapkan dengan meminta "objek". Anda dapat menggunakan ini untuk bilangan bulat jika Anda tidak keberatan memperlakukan "tidak disetel" seolah-olah "disetel ke nol".

Orang-orang yang sudah menguji ini tampaknya telah dibodohi oleh aspek negatif palsu, yaitu menguji ini dengan melihat apakah objectForKey mengembalikan nol ketika Anda tahu kunci belum ditetapkan tetapi gagal untuk memperhatikan bahwa itu juga mengembalikan nol jika kunci telah diatur tetapi telah diatur ke NO.

Untuk masalah saya sendiri, yang mengirim saya ke sini, saya akhirnya mengubah semantik boolean saya sehingga default yang saya inginkan sesuai dengan nilai yang diatur ke NO. Jika itu bukan pilihan, Anda harus menyimpan sesuatu selain boolean dan memastikan bahwa Anda dapat membedakan antara YA, TIDAK, dan "tidak disetel."

JamesKVL
sumber
Saya sudah mengkonfirmasi ini, tetapi ada solusi yang mudah; cukup gunakan objek literal baru atau ekspresi kotak. @0bukannya 0, @NObukannya NO, atau hanya @(variable). Baca tentang mereka di sini.
kaka
1
Sedikit terlambat, tetapi untuk kepentingan pemula: ini tidak benar. objek (forKey) pada nilai UserDefault dari bilangan bulat yang diatur ke 0, dan Bools yang disetel ke false, akan mengembalikan non-nil dengan benar. Jika Anda menggunakan bool (forKey) untuk menguji apakah suatu nilai ditetapkan, Anda dapat mengalami masalah (karena jika nilai tersebut disetel ke False, bool (forKey) akan mengembalikan 'false', meskipun Anda mengharapkan 'true'.)
thecloud_of_unknowing
5

Swift 3/4:

Berikut ini adalah ekstensi sederhana untuk tipe nilai kunci Int / Double / Float / Bool yang meniru perilaku pengembalian-opsional dari tipe lain yang diakses melalui UserDefaults.

( Sunting 30 Agustus 2018: Diperbarui dengan sintaksis yang lebih efisien dari saran Leo.)

extension UserDefaults {
    /// Convenience method to wrap the built-in .integer(forKey:) method in an optional returning nil if the key doesn't exist.
    func integerOptional(forKey: String) -> Int? {
        return self.object(forKey: forKey) as? Int
    }
    /// Convenience method to wrap the built-in .double(forKey:) method in an optional returning nil if the key doesn't exist.
    func doubleOptional(forKey: String) -> Double? {
        return self.object(forKey: forKey) as? Double
    }
    /// Convenience method to wrap the built-in .float(forKey:) method in an optional returning nil if the key doesn't exist.
    func floatOptional(forKey: String) -> Float? {
        return self.object(forKey: forKey) as? Float
    }
    /// Convenience method to wrap the built-in .bool(forKey:) method in an optional returning nil if the key doesn't exist.
    func boolOptional(forKey: String) -> Bool? {
        return self.object(forKey: forKey) as? Bool
    }
}

Mereka sekarang lebih konsisten di samping metode get bawaan lainnya (string, data, dll.). Cukup gunakan metode get di tempat yang lama.

let AppDefaults = UserDefaults.standard

// assuming the key "Test" does not exist...

// old:
print(AppDefaults.integer(forKey: "Test")) // == 0
// new:
print(AppDefaults.integerOptional(forKey: "Test")) // == nil
Stefan
sumber
2
Saya lebih suka return self.object(forKey: key) as? Intuntuk mencari nilai hanya sekali.
Leo
3

Saya baru saja melewati ini, dan semuanya jawaban Anda membantu saya menuju solusi yang baik, bagi saya. Saya menolak mengikuti rute yang disarankan, hanya karena saya merasa sulit untuk membaca dan memahami.

Inilah yang saya lakukan. Saya punya BOOL yang dibawa berkeliling dalam variabel yang disebut "_talkative".

Ketika saya menetapkan objek default (NSUserDefaults) saya, saya menetapkannya sebagai objek, yang kemudian dapat saya uji untuk melihat apakah nil:

//converting BOOL to an object so we can check on nil
[defaults setObject:@(_talkative) forKey:@"talkative"];

Lalu ketika saya pergi untuk melihat apakah itu ada, saya menggunakan:

if ([defaults objectForKey:@"talkative"]!=nil )
  {

Kemudian saya menggunakan objek tersebut sebagai BOOL:

if ([defaults boolForKey:@"talkative"]) {
 ...

Ini sepertinya berhasil dalam kasus saya. Itu hanya lebih masuk akal secara visual bagi saya.

james Burns
sumber
Ini bekerja untuk saya ([default boolForKey: @ "latah"]
Vineesh TP
3

Coba crumpet kecil ini:

-(void)saveUserSettings{
NSNumber*   value;

value = [NSNumber numberWithFloat:self.sensativity];
[[NSUserDefaults standardUserDefaults] setObject:value forKey:@"sensativity"];
}
-(void)loadUserSettings{
    NSNumber*   value;
    value = [[NSUserDefaults standardUserDefaults] objectForKey:@"sensativity"];
    if(value == nil){
        self.sensativity = 4.0;
    }else{
        self.sensativity = [value floatValue];
    }
}

Perlakukan segala sesuatu sebagai objek. Tampaknya bekerja untuk saya.

pepelkod
sumber
3

Versi cepat untuk mendapatkan Bool?

NSUserDefaults.standardUserDefaults().objectForKey(DefaultsIsGiver) as? Bool
Ben
sumber
1
Kenapa tidak digunakan boolForKey? NSUserDefaults.standardUserDefaults().boolForKey(DefaultsIsGiver)
JAL
1
boolForKeyakan kembali Booldan tidak Bool?, jadi jika kuncinya tidak ada Anda akan mendapatkan falsedan tidaknil
Ben
3

Perluas UserDefaultssekali untuk tidak menyalin-rekatkan solusi ini:

extension UserDefaults {

    func hasValue(forKey key: String) -> Bool {
        return nil != object(forKey: key)
    }
}

// Example
UserDefaults.standard.hasValue(forKey: "username")
mbelsky
sumber
0

Di Swift3, saya menggunakan cara ini

var hasAddedGeofencesAtleastOnce: Bool {
    get {
        return UserDefaults.standard.object(forKey: "hasAddedGeofencesAtleastOnce") != nil
    }
}

The Jawabannya adalah besar jika Anda menggunakan yang beberapa kali.

Saya harap ini membantu :)

Nikhil Manapure
sumber
-1

Swift 3.0

if NSUserDefaults.standardUserDefaults().dictionaryRepresentation().contains({ $0.0 == "Your_Comparison_Key" }){
                    result = NSUserDefaults.standardUserDefaults().objectForKey(self.ticketDetail.ticket_id) as! String
                }
Kiran Jasvanee
sumber