Alex Rivera | Logout

What's the best way to validate currency input in UITextField?

Asked 2008-12-04T21:40:08.773
18

My application allows the user to enter a numeric value (currency) in a UITextField control, but the keyboard layout that I wish was available is unfortunately not one of the built-in options, so I had to choose the "Numbers & Punctuation" option in Interface Builder. Here's the corresponding dialog window in IB:

enter image description here

So when my application asks the user for the input, it is displaying the following:

enter image description here

Which is perfectly fine, but look at all of the extra keys available to the user! One could easily enter "12;56!" in the text field, and I assume I have to validate that somehow.

So my question is: how do I validate currency values entered into a UITextField?

Edit
Report

4 Answers

10

I found this to be a relatively clean approach. I haven't tested it with non-US currencies but since it uses the NSNumberFormatter's properties I believe it should handle them correctly.

Start by setting up a formatter some place:

    formatter = [NSNumberFormatter new];
    [formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
    [formatter setLenient:YES];
    [formatter setGeneratesDecimalNumbers:YES];

Use the formatter to parse and reformat their input. It also handles shifting the number when digits are added and removed.

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *replaced = [textField.text stringByReplacingCharactersInRange:range withString:string];
    NSDecimalNumber *amount = (NSDecimalNumber*) [formatter numberFromString:replaced];
    if (amount == nil) {
        // Something screwed up the parsing. Probably an alpha character.
        return NO;
    }
    // If the field is empty (the initial case) the number should be shifted to
    // start in the right most decimal place.
    short powerOf10 = 0;
    if ([textField.text isEqualToString:@""]) {
        powerOf10 = -formatter.maximumFractionDigits;
    }
    // If the edit point is to the right of the decimal point we need to do
    // some shifting.
    else if (range.location + formatter.maximumFractionDigits >= textField.text.length) {
        // If there's a range of text selected, it'll delete part of the number
        // so shift it back to the right.
        if (range.length) {
            powerOf10 = -range.length;
        }
        // Otherwise they're adding this many characters so shift left.
        else {
            powerOf10 = [string length];
        }
    }
    amount = [amount decimalNumberByMultiplyingByPowerOf10:powerOf10];

    // Replace the value and then cancel this change.
    textField.text = [formatter stringFr
answered 2012-09-06T04:50:14.437
1

You can also use Gamma-Point solution and evaluate if *aNumber is Nil, if its Nil, then it means a character that wasnt 0-9 . or , was entered, this way you can validate just numbers, it will nil the variable if any no-number char is entered.

answered 2010-10-21T00:05:00.677
1

I Couldn't find the appropriate implementation for currency validate. Here is my variant:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

   NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];

   //if there is empty string return YES
   if([proposedString length] == 0) {
       return YES;
   }

   //create inverted set for appripriate symbols
   NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789.,"] invertedSet];

   //if side symbols is trimmed by nonNumberSet - return NO
   if([proposedString stringByTrimmingCharactersInSet:nonNumberSet].length != [proposedString length]) {
       return NO;
   }

   //if there is more than 1 symbol of '.' or ',' return NO
   if([[proposedString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@".,"]] count] > 2) {
      return NO;
   }

   //finally check is ok, return YES
   return YES;
}
answered 2012-01-17T08:43:00.063
0

Using shouldChangeCharactersInRange screws up the pop-up key board as the backspace button doesn't work.

Number formatter is the way to go. Here's a sample I used to find positive decimals. I call it during the validation check- for e.g. when the user clicks on the save button.

    -(BOOL) isPositiveNumber: (NSString *) numberString {

    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];

    NSNumber *aNumber  =  [numberFormatter numberFromString:numberString];
    [numberFormatter release];

    if ([aNumber floatValue] > 0) {
        NSLog( @"Found positive number %4.2f",[aNumber floatValue] );

        return YES;
    }
    else {
        return NO;
    }
}
answered 2010-09-04T21:21:49.483

Your Answer