NSNumber хранится в NSUserDefaults - PullRequest
6 голосов
/ 06 октября 2011

Что-то странное только что произошло.

Я сохранил NSNumber с длинным длинным значением без знака в NSUserDefaults. Когда я получаю его, значение просто изменилось. Похоже, система считает, что число длинное, а не длинное без знака.

Хуже всего то, что , когда я сравниваю число, полученное из 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 ]

6 голосов
/ 06 октября 2011

Для дальнейшего ответа на ваш вопрос.Если вы посмотрите в документации для isEqualToNumber: NSNumber , вы заметите следующую строку:

Два объекта NSNumber считаются равными, если они имеют одинаковый идентификатор значений или, если они имеют эквивалентные значения

, важно, чтобы вы это поняли.В вашем коде, который вы спрашиваете, мой объект NSNumber "число" равно "значению", вы не спрашиваете, равно ли числовое значение, сохраненное в моем объекте "NSNumber" число ", числовому значению, хранящемуся в моем объекте" NSNumber "значение".

Последняя строка кода, которую вы написали, показывает, что на самом деле числовые значения вашего NSNumber фактически равны.

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

Таким образом, вы правильно сохраняете и извлекаете значения, вы должны использовать == метод сравнения с объектами NSNumber хранит числовые значения (т.е. intValue == intValue, unsignedLongLongValue == unsignedLongLongValue) и не сравнивает их идентификаторы объектов вместе.

Что касается этой строки кода

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

Это не странно, это совершенно нормально, так как вы сказали NSLog распечатать представление NSObject 'number'.Я не уверен на 100%, но я считаю, что функция NSNumber - ( NSString * ) description по умолчанию возвращает целое число без знака для числового значения, которое оно содержит.Вот почему вы получаете большое отрицательное число.Возможно, вы захотите взглянуть на функцию - (NSString *)descriptionWithLocale:(id)aLocale NSNumber, чтобы распечатать данные более логично для вас, или вы можете использовать

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

, который даст вам правильный ответ.

РЕДАКТИРОВАТЬ:

В дополнение к этому, после изучения вопроса, происходит то, что при воспоминании вашего объекта NSNumber из UserDefaults его первоначальный тип номера не сохраняется (эта информация выделенав документации для NSNumber в разделе обзора)

(Обратите внимание, что числовые объекты не обязательно сохраняют тип, с которым они созданы.)

Вы можете увидеть это самиесли вы запишете следующее после получения «числа» из значений по умолчанию пользователя (добавьте это в конец кода, который у вас есть в вашем вопросе) и посмотрите значения кодировки, показанные здесь

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 лишает «подписанность» вашего числа.

3 голосов
/ 22 сентября 2012

В конце дня, если вы хотите сохранить NSNumber в NSUserDefaults, этот код работает для меня даже для больших целых чисел, таких как: 881217446193276338

Для сохранения:

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

Для восстановления:

self.myUser.sessionid = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"sessionid"];
1 голос
/ 06 октября 2011

Он хранится правильно, с вашим кодом все в порядке, кроме:

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

Здесь number - это нестроковый объект, вы можете думать о нем как оберткедля числового примитива.Или вы можете подумать, что NSNumber экземпляров объективируют примитивный тип.

Вам нужно что-то вроде:

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

0 голосов
/ 06 октября 2011

Вот умозрительный ответ:

Документация NSNumber гласит:

(Обратите внимание, что числовые объекты не обязательно сохраняют тип, с которым они созданы.).

Таким образом, он должен использовать другое внутреннее хранилище для этого типа и дает вам правильное значение только тогда, когда вы специально запрашиваете значение unsigned long long.Метод description, который вызывается в вашем операторе NSLog, может по умолчанию использовать другой тип представления.

И / или может быть какая-то особенность разархиватора, которая мешает методу isEqualToNumber работать со значением, возвращаемым из значений по умолчанию.Если вы сделаете это сравнение между двумя номерами NSN, созданными в одной и той же области, это сработает?Правильное значение определенно где-то там, если ваше последнее утверждение возвращает true.

...