Como incrementar um NSNumber

108

Como faço para incrementar um NSNumber?

ou seja, myNSNumber ++

O aprendiz
fonte
2
Lembre-se: ao usar NSNumber *, sempre verifique se os tipos primitivos são suficientes.
WKS de
1
Estou surpreso que não haja resposta fornecendo uma maneira rápida / otimizada de fazer isso, porque apenas para aumentar o valor você precisa consultar, combinar e criar um novo objeto, então fazer isso em loop pode se tornar demorado.
PetrV de

Respostas:

123

Atualização: Para sua informação, eu pessoalmente gosto mais das respostas de uma linha do BoltClock e do DarkDusts. Eles são mais concisos e não requerem variáveis ​​adicionais.


Para incrementar um NSNumber, você terá que obter seu valor, incrementá-lo e armazená-lo em um novo NSNumber.

Por exemplo, para NSNumbersegurar um inteiro:

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

Ou para NSNumbersegurar um número de ponto flutuante:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Itai Ferber
fonte
62
Este é o principal motivo pelo qual odeio as propriedades NSNumber no Core Data. O NSNumber é tão inconveniente de se trabalhar e fazer contas.
Christian Schlensker,
novamente NSNumber não funcionou enquanto inicializar com zero dá valor de lixo.
Jignesh B
desculpe, o que ...significa? Isso é uma referência de pseudo-código, certo? XCode não...
boulder_ruby
@boulder_ruby O ...é apenas um espaço reservado para qualquer número que você quiser.
Itai Ferber
126

NSNumberobjetos são imutáveis; o melhor que você pode fazer é pegar o valor primitivo, incrementá-lo e envolver o resultado em seu próprio NSNumberobjeto:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
fonte
28
Linguagens modernas: 1, Objective-C: 0.
devios1
77

Para quem está usando a versão mais recente do Xcode (escrevendo a partir de 4.4.1, SDK 5.1), com o uso de literais de objeto, você pode limpar o código um pouco mais ...

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

Ainda é meio chato lidar com o encaixotamento e desembalagem de tudo para fazer operações simples, mas está ficando melhor, ou pelo menos mais curto.

shortstuffsushi
fonte
6
@softRli Confira clang.llvm.org/docs/ObjectiveCLiterals.html para ver mais Literais ObjC! Muito prático.
chown
1
E, por falar nisso, você poderia usar x - @ (x.intValue + 1), embora muitas pessoas não gostem de usar a notação de ponto para invocar métodos sem propriedade. É mais curto, mas pode ser chamado de abuso da notação de ponto.
Duncan C de
@boulder_ruby, é uma reatribuição. NSNumbers são imutáveis, portanto, para "incrementar" o valor, você realmente deve reatribuí-lo a um novo valor.
shortstuffsushi
30

NSNumbers são imutáveis, você deve criar uma nova instância.

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

// EDIT: With modern syntax:
myNSNumber = @([myNSNumber longLongValue] + 1);
DarkDust
fonte
24

Junte todos eles e você terá:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
fonte
você não está reatribuindo o valor de myNSNumber aqui? Achei que isso não fosse permitido porque os NSNumberobjetos são imutáveis ​​(?)
boulder_ruby
1
Você está criando um novo objeto NSNumber. myNSNumber é um ponteiro (NSNumber *) e tem um novo valor quando você terminar.
JLundell
3

Eu gosto da expressão de ponto porque é mais concisa e é por isso que o IOS oferece suporte em primeiro lugar:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
macaco
fonte
a notação de ponto não está fazendo o que você pensa e pode ser mais lenta às vezes (pode ser padronizada como "valueForKey:" se nenhum acessador sintetizado existir para a "propriedade" (no seu caso intValue). intValue nunca foi definido como @property de NSNumber.
Motti Shneor
2

Se você estiver usando para armazenar um valor integral:

myNSNumber = @(myNSNumber.longLongValue + 1);

Para coisas de ponto flutuante, a resposta curta é a seguinte, mas é uma má ideia fazer isso, você perderá a precisão e se fizer qualquer tipo de comparação mais tarde, como [myNSNumber isEqual: @ (4.5)], você pode se surpreender :

myNSNumber = @(myNSNumber.floatValue + 1);

Se você precisar fazer matemática em números de ponto flutuante representados como objetos em Objective-C (ou seja, se precisar colocá-los em matrizes, dicionários, etc.), você deve usar NSDecimalNumber.

lms
fonte
Se você vai votar negativamente, pode muito bem ser construtivo e dizer por quê.
lms de
Sua resposta implica que é o NSNumber que apresenta problemas de arredondamento. Incorreto. NSNumber tem o mesmo comportamento de arredondamento dos tipos escalares. Além disso, seu conselho para usar NSDecimalNumbers é bastante irritante. Nesse caso, você sugere que eles são necessários se você precisar de objetos de primeiro cidadão no onmbjetivo-c. Mas, é claro, nsnumbers em objetos também. NSDecimalNumbers têm uma precisão maior, mas também podem ocorrer erros de arredondamento com eles. E: op pergunta sobre o incremento, sua resposta com float e aritmética dupla. Mas esses não têm incremento, pois não têm sucessor natural.
vikingosegundo
@vikingosegundo É a conversão de um NSNumber em um float que causa a perda de precisão porque o NSNumber armazena números abstratamente onde o float é base2, então não é culpa do NSNumber, mas da conversão para frente e para trás. E NSDecimalNumbers não causará erros de arredondamento para aritmética de base 10, e eles são projetados para aritmética, leia o documento. O OP perguntou sobre o incremento de um NSNumber, e eu dei a ele uma resposta correta e legível para o caso integral e também uma resposta para o caso de ponto flutuante, mas desaconselhei e, em seguida, segui com uma sugestão melhor.
lms de
Uma instância pode representar qualquer número que possa ser expresso como mantissa x 10 expoente, onde mantissa é um número inteiro decimal com até 38 dígitos e expoente é um número inteiro entre -128 e 127. Nem todo número pode ser expresso dessa forma. O OP também pedia um incremento fácil. NSDecimalNumber não forneceu isso. e ainda assim sua resposta implica que você precisa de NSDecimalNumbers no espaço do objeto. isso esta errado.
vikingosegundo
Cara, eu estava tentando ser genuinamente útil com minha resposta e pensei que o downvote foi porque eu entendi algo errado e pensei que poderia aprender algo novo. Eu posso ver agora que não é o caso. Seus comentários não fazem sentido e eu sugiro que você leia sobre sistemas numéricos porque um sistema numérico de base 10. (Re. Sua citação) não causará nenhum erro de arredondamento para números de base 10, eu não disse nada sobre precisão, apenas exatidão, mas 128 decimal também tem bastante precisão.
lms de
0

Use uma categoria para facilitar o uso futuro. Aqui está uma ideia básica.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
Nizx
fonte
Ugh. Uma categoria que implementa um método de instância que substitui self?!? Isso é realmente desagradável. Por que não escrever um método de instância que tenha um retorno não nulo do NSNumber resultante.
Duncan C de
NSNumber é definido como imutável, portanto, este método de categoria está violando sua suposta imutabilidade (mesmo se substituindo self). Em vez disso, uma categoria melhor projetada adicionaria um novo inicializador a NSNumber, na forma: + numberByIncrementingAmounf: (int) amount;
Motti Shneor
0

Muita informação boa nas respostas a esta pergunta. Usei a resposta selecionada no meu código e funcionou. Então comecei a ler o resto dos posts e simplifiquei muito o código. É um pouco mais difícil de ler se você não está familiarizado com as mudanças na notação que foram introduzidas no Xcode 5, mas é muito mais limpo. Eu provavelmente poderia fazer apenas uma linha, mas é um pouco difícil descobrir o que estou fazendo.

Estou armazenando um NSNumber em um dicionário e desejo incrementá-lo. Eu pego, converto em um int, incremento ao convertê-lo em um NSNumber e coloco de volta no dicionário.

Código Antigo

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

Novo Código

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
JScarry
fonte