Como usar o NSDecimalNumber?

Estou construindo um aplicativo que precisa realizar cálculos em dinheiro.

Gostaria de saber como usar corretamente NSDecimalNumber, especialmente como inicializá-lo a partir de inteiros, floats e duplos?

Eu só achei fácil usar o método -decimalNumberWithString: Os methods -initWith... são desencorajados para que só deixem os com mantissa, mas nunca em nenhum dos 7 idiomas que usei antes -initWith... disso para não saber o que colocar lá …

NÃO use os methods +numberWith... para criar objects NSDecimalNumber . Eles são declarados para retornar objects NSNumber e não são garantidos para funcionar como instâncias NSDecimalNumber .

Isto é explicado neste tópico por Bill Bumgarner, um desenvolvedor da Apple. Eu encorajaria você a registrar um bug contra esse comportamento, referenciando o erro rdar: // 6487304.

Como alternativa, estes são todos os methods apropriados para usar para criar um NSDecimalNumber :

 + (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag; + (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm; + (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue; + (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue locale:(id)locale; + (NSDecimalNumber *)zero; + (NSDecimalNumber *)one; + (NSDecimalNumber *)minimumDecimalNumber; + (NSDecimalNumber *)maximumDecimalNumber; + (NSDecimalNumber *)notANumber; 

Se você simplesmente quer um NSDecimalNumber de um float ou uma constante int tente algo assim:

 NSDecimalNumber *dn = [NSDecimalNumber decimalNumberWithDecimal: [[NSNumber numberWithFloat:2.75f] decimalValue]; 

A maneira correta é realmente fazer isso:

 NSDecimalNumber *floatDecimal = [[[NSDecimalNumber alloc] initWithFloat:42.13f] autorelease]; NSDecimalNumber *doubleDecimal = [[[NSDecimalNumber alloc] initWithDouble:53.1234] autorelease]; NSDecimalNumber *intDecimal = [[[NSDecimalNumber alloc] initWithInt:53] autorelease]; NSLog(@"floatDecimal floatValue=%6.3f", [floatDecimal floatValue]); NSLog(@"doubleDecimal doubleValue=%6.3f", [doubleDecimal doubleValue]); NSLog(@"intDecimal intValue=%d", [intDecimal intValue]); 

Veja mais informações aqui .

Em termos de design, você deve tentar evitar a conversão de NSDecimalNumber ou NSDecimals para e de int, float e double valores pelos mesmos motivos que é recomendado usar NSDecimalNumbers: perda de precisão e problemas de representação de ponto flutuante binário. Eu sei, às vezes é inevitável (tendo input de um controle deslizante, fazendo cálculos trigonométricos, etc.), mas você deve tentar receber input de usuários como NSStrings e, em seguida, usar initWithString: locale: ou decimalNumberWithString: locale: para gerar o NSDecimalNumbers. Faça toda a sua matemática com os NSDecimalNumbers e retorne sua representação para os usuários ou salve-os em SQLite (ou onde) como sua descrição de string usando descriptionWithLocale :.

Se você tiver que inserir de um int, float ou double, você poderia fazer algo como o seguinte:

 int myInt = 3; NSDecimalNumber *newDecimal = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%d", myInt]]; 

ou você pode seguir a sugestão de Ashley para ter certeza de que está seguro na construção decimal.