2010-01-03 12 views
1

iPhone/Objective-C/Cocoa newbie ici. Basé sur un certain nombre de messages sur stackoverflow, j'ai bricolé ensemble un IBAction que j'utilise dans une application de calculatrice iPhone de base que je construis. IBAction fonctionne avec le pavé numérique pour permettre la saisie de nombres décimaux sans avoir à entrer un point décimal. J'essaie très fort d'adhérer à l'adage «utiliser NSDecimal en matière de devise» bien que je trouve difficile de le faire comme tant d'autres personnes qui ont posté des questions. Je fais des progrès constants, mais j'ai frappé un mur qui, j'en suis sûr, semblera anodin après que j'ai pris connaissance de la NSDecimal et des spécifications de format.iPhone saisie de la monnaie en utilisant NSDecimal au lieu de float

Voici le IBAction J'utilise (il est déclenché par édition changé UITextField Event):

// called when user touches a key or button 
- (IBAction)processKeystrokes:(id)sender 
{ 
static BOOL toggle = YES; // was this method triggered by the user? 

// the user touched the keypad 
if (toggle) 
{ 
    toggle = NO; 

    // retrieve the strings in input fields 
    NSString *currencyField1Text = currencyField1.text; 
    NSString *currencyField2Text = currencyField2.text; 

    if (sender == currencyField1) { 
    currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""]; 
    float currency = [currencyFieldText floatValue]/100; 
    currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency]; 
    } 
    else if (sender == currencyField2) { 
    currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""]; 
    NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; 
    currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2]; 
    } 
    else { 
    NSLog(@"Some unexpected input"); 
    } 
} 
else 
{ 
    toggle = YES; 
} 

} // end method calculateResults 

Le segment de code currencyField1 utilise des flotteurs, le segment currencyField2 utilise NSDecimal. Le segment currencyField1 fonctionne comme vous le souhaitez: affiche tous les chiffres avec deux chiffres après le point décimal (même lorsque la touche de suppression est utilisée pour supprimer tous les chiffres entrés); cependant, il souffre et illustre parfaitement le problème de l'utilisation des flottants lorsqu'il s'agit de valeurs de devises importantes: des erreurs d'arrondi apparaissent lorsque les chiffres saisis dépassent 8 chiffres.

Le segment currencyField2 évite les problèmes d'arrondi en utilisant NSDecimal au lieu de float; Cependant, il n'affiche pas toujours les chiffres avec deux chiffres après la virgule décimale - cela est affiché lorsque la touche de suppression est utilisée pour supprimer tous les chiffres entrés. Je crois que le problème est dû à cette ligne de code:

currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2]; 

Ceci est le corollaire de la ligne suivante qui produit le format souhaité pour les flotteurs:

currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency]; 

Donc, je pense que je dois l'équivalent de @ "% 0.2f" pour formater l'affichage d'une valeur "0" NSDecimalNumber. Cela fait tellement d'heures que je suis gêné, mais je n'arrive pas à comprendre.

Toute aide ou pointeur sont appréciés.

EDIT: J'ai incorporé l'objet NSNumberFormatter (similaire à ce que Brad décrit dans son commentaire) qui semble avoir résolu le problème. Cependant, j'aimerais avoir des commentaires sur la refactorisation du code maintenant que je l'ai fonctionné. Voici le code révisé:

// called when user touches a key or button 
- (IBAction)processKeystrokes:(id)sender 
{ 
static BOOL toggle = YES; // was this method triggered by the user? 

// the user touched the keypad 
if (toggle) 
{ 
    toggle = NO; 

    // retrieve the strings in input fields 
    NSString *currencyField1Text = currencyField1.text; 
    NSString *currencyField2Text = currencyField2.text; 

    // new code elements 
    NSNumberFormatter * nf = [[[NSNumberFormatter alloc] init]autorelease]; 
    [nf setNumberStyle:NSNumberFormatterCurrencyStyle]; 
    [nf setCurrencySymbol:@""]; 
    [nf setCurrencyGroupingSeparator:@""]; 

    if (sender == currencyField1) { 
    currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""]; 
    NSDecimalNumber *currency = [[NSDecimalNumber decimalNumberWithString:currencyField1Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; 
    currencyField1.text = [nf stringFromNumber:currency]; 
    } 
    else if (sender == currencyField2) { 
    currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""]; 
    NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]]; 
    currencyField2.text = [nf stringFromNumber:currency2]; 
    } 
    else { 
    NSLog(@"Some unexpected input"); 
    } 
} 
else 
{ 
    toggle = YES; 
} 

} // end method calculateResults 

Il résout mon problème initial, mais j'apprécierais des conseils sur la façon de l'améliorer. Merci.

Répondre

1

Si vous voulez garantir 2 chiffres après la virgule décimale pour la valeur de votre texte, vous pouvez utiliser un NSNumberFormatter comme dans le code suivant (tiré de la réponse here):

NSNumberFormatter *decimalNumberFormatter = [[NSNumberFormatter alloc] init]; 
[decimalNumberFormatter setMinimumFractionDigits:2]; 
[decimalNumberFormatter setMaximumFractionDigits:2]; 
currencyField2.text = [decimalNumberFormatter stringFromNumber:currency2]; 
[decimalNumberFormatter release]; 

Je crois que cela devrait préserver la précision du NSDecimalNumber. Personnellement, je préfère utiliser la structure NSDecimal C pour des raisons de performance, mais c'est un peu plus difficile d'obtenir et de retirer des valeurs.

+0

Merci Brad. Votre suggestion a fonctionné, mais le «0» principal serait perdu si l'utilisateur a supprimé tous les chiffres entrés. Cela donnerait une valeur affichée de ".00" où je voulais "0.00". J'ai corrigé cela avec "[nf setNumberStyle: NSNumberFormatterCurrencyStyle];" qui a apporté les points décimaux et deux chiffres de fuite; mais aussi le symbole monétaire ("$") et le séparateur de groupe monétaire (",") que j'ai éliminé en utilisant "[nf setCurrencySymbol: @" "];" et "[nf setCurrencyGroupingSeparator: @" "];" respectivement. Merci pour le pointeur - NSNumberFormatter a résolu le problème! –

0

Vous ne pouvez pas utiliser la méthode -setFormat: (de NSNumberFormatter) à la place pour NSNumberFormatter? Il semble que l'on devrait être capable de le configurer pour vos besoins et vous n'auriez pas à faire face à des "hacks" bizarres sur une chaîne au format monétaire.

Pour plus d'informations, voir: