views:

548

answers:

3

After over a day of poking around with this problem I will see if I can get some help. This question has been more or less asked before, but it seems no one is giving a full answer so hopefully we can get it now.

Using a UILabel and a UITextView (w/ number keyboard) I want to achieve an ATM like behavior of letting the users just type the numbers and it is formatted as currency in the label. The idea is basically outlined here:

http://stackoverflow.com/questions/276382/best-way-to-enter-numeric-values-with-decimal-points

The only issue is that it never explicitly says how we can go from having an integer like 123 in the textfield and displaying in the label as $1.23 or 123¥ etc. Anyone have code that does this?

+1  A: 

Take a look at NSNumberFormatter, which will format numerical data based on the current or specified locale.

Alex Reynolds
I have looked into that, but it will take 123 and convert it to $123.00 when the idea is to convert it to $1.23
Noah Hendrix
Perhaps you could read the length of the string and, taking into consideration the locale, translate that into 1.23 -- which gets formatted as $1.23 -- instead of 123.00, which gets formatted as $123.00.
Alex Reynolds
For example, you could call `-currencyDecimalSeparator` and `-currencyGroupingSeparator` on the locale's `NSNumberFormatter` to learn how to handle formatting.
Alex Reynolds
+1  A: 

I have found a solution, and as per the purpose of this question I am going to provide a complete answer for those who have this problem in the future. First I created a new Helper Class called NumberFormatting and created two methods.

//
//  NumberFormatting.h
//  Created by Noah Hendrix on 12/26/09.
//

#import <Foundation/Foundation.h>


@interface NumberFormatting : NSObject {

}

-(NSString *)stringToCurrency:(NSString *)aString;
-(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal;

@end

and here is the implementation file:

//
//  NumberFormatting.m
//  Created by Noah Hendrix on 12/26/09.
//

#import "NumberFormatting.h"


@implementation NumberFormatting

  -(NSString *)stringToCurrency:(NSString *)aString {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if ([aString length] == 0)
      aString = @"0";

    //convert the integer value of the price to a decimal number i.e. 123 = 1.23
    //[currencyFormatter maximumFractionDigits] gives number of decimal places we need to have
    //multiply by -1 so the decimal moves inward
    //we are only dealing with positive values so the number is not negative
    NSDecimalNumber *value  = [NSDecimalNumber decimalNumberWithMantissa:[aString integerValue]
                                                                exponent:(-1 * [currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [currencyFormatter stringFromNumber:value];
  }

  -(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if (aDecimal == nil)
      aDecimal = [NSDecimalNumber zero];

    NSDecimalNumber *price  = [NSDecimalNumber decimalNumberWithMantissa:[aDecimal integerValue]
                                                                exponent:([currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [price stringValue];
  }

@end

The first method, stringToCurrency, will take an integer number (passed in from a textfield in this case) and convert it to a decimal value using moving the decimal point as appropriate for the users locale settings. It then returns a string representation formatted as currency using NSNumberFormatter.

The second method does the reverse it takes a value like 1.23 and converts it back to 123 using a similar method.

Here is an example of how I used it

...
self.accountBalanceCell.textField.text  = [[NumberFormatting alloc] decimalToIntString:account.accountBalance];
...
[self.accountBalanceCell.textField addTarget:self
                                            action:@selector(updateBalance:)
                                  forControlEvents:UIControlEventEditingChanged];

Here we set the value of the text field to the decimal value from the data store and then we set a observer to watch for changes to the text field and run the method updateBalance

- (void)updateBalance:(id)sender {
  UILabel *balanceLabel = (UILabel *)[accountBalanceCell.contentView viewWithTag:1000];
  NSString *value       = ((UITextField *)sender).text;
  balanceLabel.text     = [[NumberFormatting alloc] stringToCurrency:value];
}

Which simply takes the textfield value and run it through the stringToCurrency method described above.

To me this seems hackish so please take the a moment to look over and clean it up if you are interested in using it. Also I notice for large values it breaks.

Noah Hendrix
A: 

Noah's answer leaks. NSNumberFormatter need autorelease or release before return.

Battery