发生了一件奇怪的事。
我在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
答案 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,正确的值肯定在某处。