NSNumber存储在NSUserDefaults中

Swo*_*rog 6 iphone nsuserdefaults nsnumber ios

刚刚发生了一件奇怪的事.

我在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
Run Code Online (Sandbox Code Playgroud)

Jam*_*art 6

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

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

你理解这一点很重要.在您的代码中,您要求的是我的NSNumber对象"number"等于"value",您不是要求我的NSNumber对象"number"中存储的数值是否等于存储在我的NSNumber对象"value"中的数值.

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

NSLog(@"%d", [number unsignedLongLongValue] == value); //1
Run Code Online (Sandbox Code Playgroud)

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

至于这行代码

NSLog(@"Current Number:%@", number); // -2538698204676668398, weird
Run Code Online (Sandbox Code Playgroud)

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

NSLog(@"Current Number:%llu", [number unsignedLongLongValue]);
Run Code Online (Sandbox Code Playgroud)

哪个会给你正确的答案.

编辑:

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

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

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

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

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

NSNumber *number = [NSNumber numberWithUnsignedLongLong:[[NSUserDefaults standardUserDefaults] objectForKey:NumberKey] unsignedLongLongValue]];
Run Code Online (Sandbox Code Playgroud)

您可以查看使用NSNumber compare:函数来查看返回的值是否为NSOrderedSame但是这不适用于比较相同类型的无符号与有符号值,因此在您的情况下我将使用上述方法从NSUserDefaults检索数据是剥夺你号码的"签名".