NSNumber存储在NSUserDefaults中

时间:2011-10-06 05:32:59

标签: iphone ios nsuserdefaults nsnumber

发生了一件奇怪的事。

我在NSUserDefaults中存储了一个带有unsigned long long值的NSNumber。当我检索它时,值只是改变了。似乎系统认为数字很长而不是无符号多长。

更糟糕的是当我将从UserDefaults检索到的数字与原始数字进行比较时,结果是NotEqual

代码有什么问题?谢谢!

static NSString * const NumberKey = @"MyNumber";
unsigned long long value = 15908045869032883218ULL;
if ([[NSUserDefaults standardUserDefaults] objectForKey:NumberKey] == nil) {

    NSNumber *number = [NSNumber numberWithUnsignedLongLong:value];
    [[NSUserDefaults standardUserDefaults] setObject:number forKey:NumberKey];
    NSLog(@"Original Number:%@", number); // 15908045869032883218, right
}

NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:NumberKey];
NSLog(@"Current Number:%@", number); // -2538698204676668398, weird
NSLog(@"Current Value:%llu", [number unsignedLongLongValue]); // 15908045869032883218, right
NSLog(@"%d", [number isEqualToNumber:[NSNumber numberWithUnsignedLongLong:value]]); // 0
NSLog(@"%d", [number unsignedLongLongValue] == value); // 1

4 个答案:

答案 0 :(得分:6)

进一步回答你的问题。如果您查看documentation for NSNumber的isEqualToNumber:函数,您会注意到以下行,

  

如果两个NSNumber对象具有相同的 id 值,或者它们具有相同的值,则认为它们相等

了解这一点非常重要。在您的代码中,您要问的是我的NSNumber对象“number”等于“value”,您不是要求我的NSNumber对象“number”中存储的数值是否等于存储在我的NSNumber对象“value”中的数值。

您编写的最后一行代码表明,实际上您的NSNumber的数值实际上相等。

NSLog(@"%d", [number unsignedLongLongValue] == value); //1

因此,您正确地存储和检索值,您应该使用==比较方法与NSNumber对象存储数值(即intValue == intValue,unsignedLongLongValue == unsignedLongLongValue)并且不将它们的对象ID进行比较。

至于这行代码

NSLog(@"Current Number:%@", number); // -2538698204676668398, weird

这并不奇怪,这是完全正常的,因为你告诉NSLog打印出'number'的NSObject表示。我不是100%肯定,但我相信NSNumber的- ( NSString * ) description函数默认返回它包含的数值的无符号整数值。这就是为什么你得到返回的大负数。您可能希望查看NSNumber的- (NSString *)descriptionWithLocale:(id)aLocale函数,以便为您更合理地打印数据,或者您可以使用

NSLog(@"Current Number:%llu", [number unsignedLongLongValue]);

这会给你正确的答案。

修改

此外,在查看问题之后发生的事情是,从UserDefaults重新收集您的NSNumber对象时,它的原始数字类型未被保留(此信息在概述部分的NSNumber文档中突出显示)

  

(请注意,数字对象不一定保留使用它们创建的类型。)

如果您在从用户默认值中检索“数字”之后记录以下内容,您可以自己查看此内容(将其添加到您在问题中的代码末尾),并查看显示的编码值here

NSLog(@"%s", [number objCType]); //This will log out q
NSLog(@"%s", [[NSNumber numberWithUnsignedLongLong:value] objCType]); //this will log out Q

Q和q之间的区别在于Q是无符号值...因此,为什么你遇到了isEqualToNumber:函数的问题,因为数字类型不同。 如果您已经设置使用iSEqualToNumber:函数来比较值,那么您可以实现此功能以从NSUserDefaults中检索您的值。

NSNumber *number = [NSNumber numberWithUnsignedLongLong:[[NSUserDefaults standardUserDefaults] objectForKey:NumberKey] unsignedLongLongValue]];

您可以查看使用NSNumber compare:函数来查看返回的值是否为NSOrderedSame但是这对于比较相同类型的无符号与有符号值无效,因此在您的情况下我会使用上面的方法来检索数据来自NSUserDefaults正在剥夺你号码的“签名”。

答案 1 :(得分:3)

如果你想将NSNumber存储到NSUserDefaults中,那么这个代码对我来说即使对于大整数也是如此:881217446193276338

保存:

[[NSUserDefaults standardUserDefaults] setObject:self.myUser.sessionid forKey:@"sessionid"];
[[NSUserDefaults standardUserDefaults] synchronize];

要恢复:

self.myUser.sessionid = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"sessionid"];

答案 2 :(得分:1)

正确存储它,除了以下代码之外没有任何问题:

NSLog(@"Current Number:%@", number);

这里number是一个非字符串对象,您可能会将其视为数字原语的包装器。或者您可能认为NSNumber实例客观化了一种原始类型。

你需要的是:

NSLog(@"Current Number:%@", [number stringValue]);

答案 3 :(得分:0)

这是一个推测性答案:

NSNumber文档指出:

  

(请注意,数字对象不一定保留使用它们创建的类型。)。

因此,它必须为此类型使用不同的内部存储,并且只在您明确要求unsigned long long值时才为您提供正确的值。在NSLog语句中调用的description方法可能默认为不同的表示类型。

和/或unarchiver可能有一些怪癖阻止isEqualToNumber方法处理默认值返回的值。如果在同一范围内创建的两个NSNumber之间进行比较,它是否有效?鉴于您的最后一个语句返回true,正确的值肯定在某处。