Как увеличить NSNumber

108

Как увеличить NSNumber?

т.е. myNSNumber ++

TheLearner
источник
2
Помните: при использовании NSNumber *всегда проверяйте, достаточно ли примитивных типов.
WKS
1
Я удивлен, что нет ответа, обеспечивающего быстрый / оптимизированный способ сделать это, потому что просто для увеличения значения вам нужно запрашивать, объединять и создавать новый объект, поэтому выполнение этого в цикле может занять много времени.
PetrV

Ответы:

123

Обновление: к вашему сведению, мне лично больше нравятся однострочные ответы BoltClock и DarkDusts. Они более краткие и не требуют дополнительных переменных.


Чтобы увеличить значение NSNumber, вам нужно будет получить его значение, увеличить его и сохранить в новомNSNumber .

Например, для NSNumberцелого числа:

NSNumber *number = [NSNumber numberWithInt:...];
int value = [number intValue];
number = [NSNumber numberWithInt:value + 1];

Или для NSNumberхранения числа с плавающей запятой:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Итаи Фербер
источник
62
Это главная причина, по которой я ненавижу свойства NSNumber в Core Data. NSNumber настолько неудобен для работы и вычислений.
Кристиан Шленскер,
снова NSNumber не работает, а инициализация с нулевым значением дает значение мусора.
Jignesh B
извините, что означает ...подставка? Это ссылка на псевдокод, верно? XCode не делает...
boulder_ruby
@boulder_ruby ...- это просто заполнитель для любого числа, которое вы хотите.
Итаи Фербер
126

NSNumberобъекты неизменны; Лучшее, что вы можете сделать, это взять примитивное значение, увеличить его, а затем обернуть результат в отдельный NSNumberобъект:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
источник
28
Современные языки: 1, Objective-C: 0.
devios1
77

Для тех, кто использует последнюю версию Xcode (пишет это как 4.4.1, SDK 5.1), с использованием объектных литералов вы можете очистить код еще немного ...

NSNumber *x = @(1);
x = @([x intValue] + 1);
// x = 2

По-прежнему сложно иметь дело с упаковкой и распаковкой всего, что нужно для выполнения простых операций, но это становится лучше или, по крайней мере, короче.

shortstuffsushi
источник
6
@softRli Посетите clang.llvm.org/docs/ObjectiveCLiterals.html, чтобы увидеть больше литералов ObjC! Имо очень удобно.
chown
1
И в этом отношении вы можете использовать x - @ (x.intValue + 1), хотя многие люди не любят использовать точечную нотацию для вызова методов, не относящихся к свойствам. Он короче, но его можно назвать злоупотреблением точечной нотацией.
Duncan C
@boulder_ruby, это переназначение. NSNumbers неизменяемы, поэтому для «увеличения» значения вы фактически должны переназначить его на новое значение.
shortstuffsushi
30

NSNumbers неизменяемы, вам нужно создать новый экземпляр.

// Work with 64 bit to support very large values
myNSNumber = [NSNumber numberWithLongLong:[myNSNumber longLongValue] + 1];

// EDIT: With modern syntax:
myNSNumber = @([myNSNumber longLongValue] + 1);
DarkDust
источник
24

Сложите их все вместе, и вы получите:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
источник
разве вы не переназначаете значение myNSNumber здесь? Я думал, что это запрещено, потому что NSNumberобъекты неизменяемы (?)
boulder_ruby
1
Вы создаете новый объект NSNumber. myNSNumber - это указатель (NSNumber *), и когда вы закончите, у него будет новое значение.
JLundell
3

Мне нравится точечное выражение, потому что оно более краткое, и именно поэтому IOS поддерживает его в первую очередь:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
разъем
источник
точечная нотация не делает то, что вы думаете, и иногда может быть медленнее (по умолчанию может быть "valueForKey:", если не существует синтезированного аксессора для "свойства" (в вашем случае intValue). intValue никогда не определялся как @property из NSNumber
Мотти Шнеор
2

Если вы используете его для хранения целочисленного значения:

myNSNumber = @(myNSNumber.longLongValue + 1);

Для вещей с плавающей запятой краткий ответ следующий, но делать это - плохая идея, вы потеряете точность, и если вы позже будете проводить какое-либо сравнение, например [myNSNumber isEqual: @ (4.5)], вы можете быть удивлены :

myNSNumber = @(myNSNumber.floatValue + 1);

Если вам нужно выполнить математические вычисления с числами с плавающей запятой, представленными как объекты в Objective-C (т.е. если вам нужно поместить их в массивы, словари и т. Д.), Вы должны использовать NSDecimalNumber.

Пленки
источник
Если вы собираетесь проголосовать против, то можно быть конструктивным и сказать, почему.
lms 07
Ваш ответ подразумевает, что именно NSNumber вызывает проблемы округления. Это неверно, NSNumber имеет то же поведение округления, что и скалярные типы. Также довольно раздражает ваш совет использовать NSDecimalNumbers. Здесь вы подразумеваете, что они необходимы, если вам нужны объекты первого гражданина в onmbjective-c. Но, конечно, и на объектах n чисел. NSDecimalNumbers имеют более высокую точность, но с ними также может возникать ошибка округления. И: op спрашивает об увеличении, ваш ответ с плавающей запятой и двойной арифметикой. Но у них нет приращения, так как у них нет естественного наследника.
vikingosegundo 07
@vikingosegundo Преобразование NSNumber в число с плавающей запятой приводит к потере точности, потому что NSNumber хранит числа абстрактно, где float - это base2, так что это не ошибка NSNumber, а ошибка преобразования туда и обратно. И NSDecimalNumbers будет не причина ошибок округления для base10 арифметических, и они будут предназначены для арифметика, прочитать документ. OP спросил об увеличении NSNumber, и я дал ему правильный и читаемый ответ для интегрального случая, а также дал ответ для случая с плавающей запятой, но посоветовал этого не делать, а затем последовал более удачное предложение.
lms 08
Экземпляр может представлять любое число, которое может быть выражено как показатель степени мантиссы x 10, где мантисса - десятичное целое число длиной до 38 цифр, а показатель степени - целое число от -128 до 127. Не каждое число можно выразить таким образом. Также OP попросил легкое увеличение. NSDecimalNumber не предусматривает этого. и все же ваш ответ подразумевает, что вам нужны NSDecimalNumbers в пространстве объектов. это не правильно.
vikingosegundo 08
Чувак, я пытался быть по-настоящему полезным своим ответом, и подумал, что отрицательный голос вызван тем, что я что-то не так понял, и я подумал, что могу узнать что-то новое. Теперь я понимаю, что это не так. Ваши комментарии не имеют смысла, и я предлагаю вам прочитать uo о системах счисления, потому что система чисел с основанием 10 sys. (Re. Ваша цитата) не вызовет ошибок округления для десятичных чисел с основанием, я ничего не сказал о точности, только о точности, но десятичное число 128 также имеет большую точность.
lms 08
0

Используйте категорию, чтобы упростить использование в будущем. Вот основная идея.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
Низкс
источник
Тьфу. Категория, реализующая метод экземпляра, заменяющий self?!? Это серьезно противно. Почему бы не написать метод экземпляра, который имеет непустой возврат результирующего NSNumber.
Duncan C
NSNumber определяется как неизменяемый, поэтому этот метод категории нарушает его предполагаемую неизменяемость (даже если заменяет self). Лучше спроектированная такая категория вместо этого добавила бы новый инициализатор к NSNumber в форме: + numberByIncrementingAmounf: (int) amount;
Мотти Шнеор
0

В ответах на этот вопрос много полезной информации. Я использовал выбранный ответ в своем коде, и он сработал. Затем я начал читать остальные сообщения и сильно упростил код. Это немного сложнее читать, если вы не знакомы с изменениями в нотации, которые были введены в Xcode 5, но это намного чище. Я, наверное, мог бы сделать всего одну строчку, но тогда слишком сложно понять, что я делаю.

Я храню NSNumber в словаре и хочу увеличить его. Я получаю его, конвертирую в int, увеличиваю при преобразовании в NSNumber, а затем возвращаю в словарь.

Старый код

 NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
 int correctValue = [correct intValue];
 correct = [NSNumber numberWithInt:correctValue + 1];
 [scoringDictionary removeObjectForKey:@"correct"];
 scoringDictionary[@"correct"] = correct;

Новый код

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
JScarry
источник