NSUserDefaults - Hier erfahren Sie, ob ein Schlüssel vorhanden ist


208

Ich arbeite an einer kleinen iPhone-App und verwende sie NSUserDefaultsals Datenpersistenz. Es muss nur ein paar Dinge im Auge behalten, wie zum Beispiel einige Namen und einige Zahlen, also denke ich, ich könnte es genauso gut einfach halten.

Ich habe diese Seite als Referenz gefunden, aber ich glaube nicht, dass sie meine Frage beantworten kann. Grundsätzlich möchte ich überprüfen können, ob ein Wert (oder ein Schlüssel) bereits in der vorhanden ist, NSUserDefaultsund dann etwas entsprechend tun.

Einige Beispiele: Die App wird gestartet. Wenn sie zum ersten Mal gestartet wird, wird eine Warnung mit der Aufschrift "Willkommen" ausgegeben. Um festzustellen, ob dies das erste Mal ist, dass es geöffnet wird, liest es das UserDefaultsund prüft.

Beispiel 2: Es heißt "Hallo [Name]", wobei Name etwas ist, das Sie eingegeben haben. Wenn Sie die App geöffnet haben und keinen Namen haben, sollte dort "Hallo Welt" stehen. Ich muss überprüfen, ob Sie bereits einen Namen eingegeben haben, und entsprechend handeln. Der Name würde in gespeichert NSUserDefaults.

Hilfe hier? Ich würde es wirklich schätzen!

Antworten:


381

objectForKey:wird zurückkehren, nilwenn es nicht existiert.


1
Ich glaube nicht, dass Sie einen primitiven Datentyp in den NSUserDefaults speichern können.
Kender

12
In den Apple-Dokumenten heißt es: "Wenn in den Benutzerstandards ein boolescher Wert mit defaultName verknüpft ist, wird dieser Wert zurückgegeben. Andernfalls wird NO zurückgegeben." Ich denke nicht, dass die obige Antwort für BOOLs richtig ist. Sie können nicht feststellen, ob sie als NEIN definiert ist oder nicht existiert. Ich denke, Sie müssten – dictionaryRepresentationden Schlüssel verwenden und nach ihm suchen.
Zekel

40
@zekel Anstatt zu raten, habe ich dies getestet (unter iOS 5.1.1) und es wurde definitiv festgestellt, ob ein BOOL vorhanden war oder nicht, unabhängig davon, welchen Wert dieses BOOL haben könnte. "objectForKey" gab null zurück, wenn das BOOL nicht vorhanden war, weil es nie gesetzt worden war.
DataGraham

8
Wenn Sie ein BOOL haben und es mit boolForKey testen, dann ist @zekel richtig, Sie erhalten JA oder NICHT. Wenn Sie es mit objectForKey testen (wie die Antwort andeutet), erhalten Sie null, wenn der Schlüssel nicht gesetzt ist.
Giuseppe Garassino

2
Dies funktioniert zumindest ab iOS 6.1 Simulator nicht mehr. objectForKey gibt denselben Wert zurück, wenn er nicht vorhanden ist und wenn er mit einem BOOL von NO vorhanden ist. Die Lösung von i.jameelkhan funktioniert
lschult2

98

Wie oben erwähnt, funktioniert es nicht für primitive Typen, bei denen 0 / NO ein gültiger Wert sein könnte. Ich benutze diesen Code.

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

    NSLog(@"mykey found");
}

Das hat mich gerettet. Vielen Dank!
BalestraPatrick

Dies ist die richtige Antwort, wenn es um Primitive wie geht BOOL. Im NOGegensatz dazu wird genau unterschieden und nicht eingestellt objectForKey:.
Devios1

@ devios1 - Wenn der Schlüssel fehlt, objectForKey:wird nilunabhängig von der Absicht des Programmierers, einen Booloder einen anderen Datentyp zu speichern, zurückgegeben . Wenn ein Grundelement vorhanden ist, wird objectForKey:es nicht zurückgegeben, nilselbst wenn der Schlüssel einem Grundelement zugeordnet ist.
Ted Hopp

Dies ist die richtige Antwort: Offensichtlich ist die akzeptierte Antwort falsch, da objectForKey 0 mit null verwechselt, sodass es nicht funktionieren kann. Erfolgreich getestet von iOS 4.3 bis 10.2.1
Chrysotribax

Ich weiß, dass dies alt ist, aber da ich diese Informationen erst jetzt benötigt habe, muss ich darauf hinweisen, dass die Referenz 'includesObject:' genau das bedeutet: das Objekt. NICHT der Schlüssel. IOW, in Ihrer Header-Datei, wenn Sie definiert haben: #define kMyKey @ "myKey", sucht das 'includesObject' nicht nach 'kMyKey', sondern nach 'myKey'. Wenn Sie 'kMyKey' verwenden, wird immer 'NO' zurückgegeben.
Bill Norman

55

Die objectForKey:Methode wird zurückgegeben, nilwenn der Wert nicht vorhanden ist. Hier ist ein einfacher IF / THEN-Test, der Ihnen sagt, ob der Wert Null ist:

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

6

" objectForKey gibt nil zurück, wenn es nicht existiert. " Es gibt auch nil zurück, wenn es existiert und es ist entweder eine Ganzzahl oder ein Boolescher Wert mit dem Wert Null (dh FALSE oder NO für den Booleschen Wert).

Ich habe dies im Simulator für 5.1 und 6.1 getestet. Dies bedeutet, dass Sie nicht wirklich testen können, ob Ganzzahlen oder Boolesche Werte festgelegt wurden, indem Sie nach "dem Objekt" fragen. Sie können damit für ganze Zahlen durchkommen, wenn es Ihnen nichts ausmacht, "nicht gesetzt" so zu behandeln, als wäre es "auf Null gesetzt".

Die Personen, die dies bereits getestet haben, scheinen durch den falsch-negativen Aspekt getäuscht worden zu sein, dh sie testen dies, indem sie prüfen, ob objectForKey null zurückgibt, wenn Sie wissen, dass der Schlüssel nicht gesetzt wurde, aber nicht bemerken, dass es auch null zurückgibt, wenn der Schlüssel vorhanden ist gesetzt, wurde aber auf NEIN gesetzt.

Für mein eigenes Problem, das mich hierher geschickt hat, habe ich gerade die Semantik meines Booleschen Werts so geändert, dass meine gewünschte Standardeinstellung mit dem auf NO gesetzten Wert übereinstimmt. Wenn dies keine Option ist, müssen Sie sie als etwas anderes als einen Booleschen Wert speichern und sicherstellen, dass Sie den Unterschied zwischen JA, NEIN und "Nicht festgelegt" erkennen können.


Ich habe dies bestätigt, aber es gibt eine einfache Lösung. Verwenden Sie einfach die neuen Objektliterale oder einen Boxed-Ausdruck. @0statt 0, @NOstatt NOoder einfach @(variable). Lesen Sie hier darüber.
Kaka

1
Ein bisschen spät, aber zum Vorteil von Neulingen: Das ist falsch. object (forKey) on UserDefault-Werte von Ganzzahlen, die auf 0 und Bools auf false gesetzt sind, geben korrekt Nicht-Null zurück. Wenn Sie bool (forKey) verwenden, um zu testen, ob ein Wert festgelegt ist, können Probleme auftreten (denn wenn der Wert auf False festgelegt ist, gibt bool (forKey) 'false' zurück, obwohl Sie 'true' erwarten.)
thecloud_of_unknowing

5

Swift 3/4:

Hier ist eine einfache Erweiterung für Int / Double / Float / Bool-Schlüsselwerttypen, die das optionale Rückgabeverhalten der anderen Typen nachahmt, auf die über UserDefaults zugegriffen wird.

( Bearbeiten 30. August 2018: Aktualisiert mit effizienterer Syntax aus Leos Vorschlag.)

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
    }
}

Sie sind jetzt konsistenter als die anderen integrierten get-Methoden (Zeichenfolge, Daten usw.). Verwenden Sie einfach die get-Methoden anstelle der alten.

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

2
Ich würde es vorziehen return self.object(forKey: key) as? Int, Wert nur einmal zu suchen.
Leo

3

Ich habe das gerade durchgearbeitet, und all Ihre Antworten haben mir geholfen, eine gute Lösung für mich zu finden. Ich habe mich geweigert, den von vorgeschlagenen Weg zu gehen, nur weil ich es schwer fand, ihn zu lesen und zu verstehen.

Folgendes habe ich getan. Ich hatte ein BOOL in einer Variablen namens "_talkative" herumgetragen.

Wenn ich mein Standardobjekt (NSUserDefaults) festlege, lege ich es als Objekt fest, da ich dann testen kann, ob es null ist:

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

Als ich dann nachschaute, ob es existiert, benutzte ich:

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

Dann habe ich das Objekt als BOOL verwendet:

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

Dies scheint in meinem Fall zu funktionieren. Es machte für mich nur mehr visuellen Sinn.


Dies funktionierte für mich ([Standardeinstellung boolForKey: @ "
talkative

3

Probieren Sie diese kleine Fladenbrot:

-(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];
    }
}

Behandle alles als Objekt. Scheint für mich zu arbeiten.


3

Schnelle Version zu bekommen Bool?

NSUserDefaults.standardUserDefaults().objectForKey(DefaultsIsGiver) as? Bool

1
Warum nicht verwenden boolForKey? NSUserDefaults.standardUserDefaults().boolForKey(DefaultsIsGiver)
JAL

1
boolForKeywird zurückkehren Boolund nicht Bool?, also wenn der Schlüssel nicht da ist, werden Sie bekommen falseund nichtnil
Ben

3

Erweitern Sie UserDefaultseinmal nicht copy-paste diese Lösung:

extension UserDefaults {

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

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

0

In Swift3 habe ich auf diese Weise verwendet

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

Die Antwort ist großartig, wenn Sie das mehrmals verwenden möchten.

Ich hoffe, es hilft :)


-1

Swift 3.0

if NSUserDefaults.standardUserDefaults().dictionaryRepresentation().contains({ $0.0 == "Your_Comparison_Key" }){
                    result = NSUserDefaults.standardUserDefaults().objectForKey(self.ticketDetail.ticket_id) as! String
                }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.