2011-10-06 103 views
6

发生了一些奇怪的事情。存储在NSUserDefaults中的NSNumber

我在NSUserDefaults中存储了一个带有无符号long long值的NSNumber。当我检索它时,值刚刚改变。看起来系统认为这个数字很长而不是无符号的long long。

更糟糕的是,当我比较从原来的号码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 

回答

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打印出“数字”的一个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比较:功能,看看如果返回值是NSOrderedSame然而,这不适用于VS相同类型的符号值在您的情况比较无符号的,所以我会用上述工作因为从NSUserDefaults中检索数据会剥离您的号码的“签名”。

+0

我同意你的意见。但是,“如果两个NSNumber对象具有相同的id值或者它们具有相同的值,则认为它们是相等的”意味着我可以依赖isEqualToNumber:来确定两个NSNumber对象的值,但是我的代码的结果显示I不能依靠这种方法。我必须自己决定值类型,并使用“XXValue”方法和“==”来比较两个NSNumber对象,这是不方便的,因为isEqual:方法用于许多其他对象,如NSArray,NSDictionary。 – Swordsfrog

+0

@Swordfrog稍微深入研究一下您的问题的本质也与下面的答案有关。我将编辑我的原始答案以证明这一点。 –

+0

谢谢,这只是解决了我的问题。 – Swordsfrog

1

它正确地存放,没有什么是你的代码错误除外:

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

这里number是一个非字符串对象,你可能会认为它是一个包装的数值基本。或者您可能认为NSNumber实例将对象化为原始类型。

你需要的是一些事情,如:

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

+0

我想知道的是,为什么从NSUserDefaults检索到的数字不等于原始数字。 – Swordsfrog

0

这里是一个投机性的答案:

的NSNumber的文档指出:

(请注意,数量的对象不必然保留它们创建的类型。)。

因此,它必须为此类型使用不同的内部存储器,并且只有在您特别要求无符号long long值时才会给出正确的值。在您的NSLog语句中调用的description方法可能会默认为不同的表示类型。

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

+0

你在这个答案正确的轨道上。做得很好。 –

3

在,如果你想的NSNumber存储到NSUserDefaults的这段代码的一天结束对我的作品即使是大的整数,如:881217446193276338

为了节省:

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

要恢复:

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

我很高兴我写了这个答案,因为6个月后,我遇到了同样的问题,我GOOGLE了它,并在这里降落,看到我自己的答案,它再次解决了我的问题:) – Ali