NSUserDefaults-如何判断密钥是否存在


208

我正在开发一个小型iPhone应用程序,并且将其NSUserDefaults用作数据持久性。它只需要跟踪一些事情,例如一些名称和数字,所以我想我也可以保持简单。

我找到此页面仅供参考,但我认为它不能回答我的问题。基本上,我希望能够检查中是否已存在值(或键)NSUserDefaults,然后进行相应的操作。

一些示例:该应用程序启动,如果这是它第一次启动,它将输出一条警告消息,表示欢迎。要知道这是第一次打开它,它会读取UserDefaults和检查。

示例2:它显示“ Hello [Name]”,其中Name是您输入的内容。如果您已打开该应用程序且没有名称,则应显示“ Hello World”。我需要检查您是否已经输入名称并采取相应措施。该名称将存储在中NSUserDefaults

这里有帮助吗?我真的很感激!

Answers:


382

objectForKey:nil如果不存在,将返回。


1
我认为您不能在NSUserDefaults中存储原始数据类型。
kender

12
苹果公司的文档说:“如果布尔值与用户默认值中的defaultName关联,则返回该值。否则,返回NO。” 我认为上述答案对BOOL并不正确,您无法确定它是否定义为NO或不存在。我认为您必须使用– dictionaryRepresentation并检查密钥。
zekel '02

40
@zekel而不是猜测,我在iOS 5.1.1上进行了测试,它可以确定是否存在BOOL,而与所说的BOOL的值无关。当BOOL不存在时,“ objectForKey”返回nil,因为从未设置过。
DataGraham

8
如果您拥有BOOL并使用boolForKey对其进行测试,则@zekel是正确的,您将获得YES或NOT。如果使用objectForKey进行测试(如答案所示),并且未设置密钥,则结果为nil。
朱塞佩·加拉西诺

2
至少从iOS 6.1 Simulator起,此功能不再起作用。如果不存在,并且BOOL为NO,则objectForKey返回相同的值。i.jameelkhan的解决方案确实有效
lschult2

98

如上所述,它不适用于原始类型,其中0 / NO可能是有效值。我正在使用此代码。

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

    NSLog(@"mykey found");
}

这救了我。谢谢!
BalestraPatrick

这是处理诸如的原始数据时的正确答案BOOLNO不同于,它将准确区分和不设置objectForKey:
devios1 2015年

@ devios1-如果缺少密钥,objectForKey:nil无论程序员最终存储a Bool或任何其他数据类型的意图如何,都将返回。存在基元时,即使键与基元值关联objectForKey:也不会返回nil
泰德·霍普

这是正确的答案:显然,由于objectForKey将0与nil混淆,因此可接受的答案是错误的,因此它无法工作。已成功从iOS 4.3测试到10.2.1
Chrysotribax

我知道这很旧,但是直到现在才需要此信息,我需要指出,“ containsObject:”引用的含义仅在于:对象。不是关键。IOW,如果已定义头文件:#define kMyKey @“ myKey”'containsObject'不是在寻找'kMyKey',而是在寻找'myKey'。使用“ kMyKey”将始终返回“ NO”。
比尔·诺曼

55

如果该值不存在,则该objectForKey:方法将返回nil。这是一个简单的IF / THEN测试,它将告诉您该值是否为nil:

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

6

objectForKey如果不存在,则将返回nil ”如果它确实存在,并且也将是一个整数或值为零的布尔值(即布尔值为FALSE或NO),它还将返回nil。

我已经在模拟器中针对5.1和6.1进行了测试。这意味着您不能真正通过询问“对象”来测试已设置的整数或布尔值。如果您不介意将“未设置”视为“设置为零”,则可以使用整数。

已经测试过此方法的人似乎被错误的否定方面所愚弄,即通过在您知道尚未设置键的情况下查看objectForKey是否返回nil来进行测试,但是没有注意到如果键已经被设置则它也返回nil。设置,但已设置为NO。

对于我自己的问题,这使我发到这里,我只是改变了布尔值的语义,以使我想要的默认值与设置为NO的值一致。如果这不是一个选择,则需要将其存储为布尔值以外的其他值,并确保您可以区分YES,NO和“未设置”之间的区别。


我已经证实了这一点,但是有一个简单的解决方案。只需使用新的对象文字或带框的表达式即可。@0代替0@NO代替NO,或简单地@(variable)在这里阅读有关它们的信息。
卡卡

1
有点晚了,但是为了新手的利益:这是不正确的。UserDefault上的object(forKey)的整数值设置为0,布尔值设置为false,将正确返回non-nil。如果使用bool(forKey)测试是否设置了值,则可能会遇到问题(因为如果将值设置为False,即使您期望的是“ true”,bool(forKey)也会返回“ false”。)
thecloud_of_unknowing

5

迅捷3/4:

这是Int / Double / Float / Bool键值类型的简单扩展,它模仿通过UserDefaults访问的其他类型的Optional-return行为。

编辑2018年8月30日:根据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
    }
}

现在,它们与其他内置的get方法(字符串,数据等)更加一致。只需使用get方法代替旧方法即可。

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
我希望return self.object(forKey: key) as? Int只搜索一次值。
狮子座

3

我刚刚经历了这个过程,您的所有回答对我来说为我提供了一个很好的解决方案。我拒绝走建议的路线,只是因为我觉得很难阅读和理解。

这就是我所做的。我有一个BOOL被带到一个名为“ _talkative”的变量中。

设置默认对象(NSUserDefaults)时,将其设置为对象,然后可以测试其是否为零:

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

然后,当我去查看它是否存在时,我使用了:

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

然后,我将该对象用作BOOL:

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

就我而言,这似乎可行。对我而言,它更具视觉感。


这对我有用([defaults boolForKey:@“ talkative”]
Vineesh TP

3

试试这个小手脚:

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

将一切都视为对象。似乎为我工作。


3

Swift版本获得 Bool?

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

1
为什么不使用boolForKeyNSUserDefaults.standardUserDefaults().boolForKey(DefaultsIsGiver)
2016年

1
boolForKey将返回Bool而不是Bool?,因此,如果钥匙不存在,您将得到false而不是nil
Ben

3

扩展UserDefaults一次即可不复制粘贴此解决方案:

extension UserDefaults {

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

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

0

在Swift3中,我以这种方式使用

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

答案,如果你是使用多次是巨大的。

希望对您有所帮助:)


-1

斯威夫特3.0

if NSUserDefaults.standardUserDefaults().dictionaryRepresentation().contains({ $0.0 == "Your_Comparison_Key" }){
                    result = NSUserDefaults.standardUserDefaults().objectForKey(self.ticketDetail.ticket_id) as! String
                }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.