2011-10-06 48 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

相關問題