Как установить значение строки валюты в UITextField, сохранив кодировку?

Я разрабатываю приложение, в котором я хочу обрабатывать разные форматы валюты, в зависимости от текущей локали. Используя NSNumberFormatter, я могу без проблем правильно перевести число в строку и обратно.

Но если я помещу строковое значение в UITextField и позже получу его обратно, я не смогу преобразовать строку обратно в число и вместо этого получу значение nil.

Вот пример кода для объяснения проблемы:

NSNumberFormatter *nf = [Utils currencyFormatter];
NSNumber *n = [NSNumber numberWithInt:10000];
NSString *s = [nf stringFromNumber:n];
NSLog(@"String value = %@", s);
UITextField *t = [[UITextField alloc] init];
// I put the string into the text field ...
t.text = s;

// ... and later I get the value back
s = t.text;
NSLog(@"Text field text = %@", s);
n = [nf numberFromString:s];
NSLog(@"Number value = %d", [n intValue]);

где метод currencyFormatter определяется следующим образом:

+ (NSNumberFormatter *)currencyFormatter
{
    static NSNumberFormatter *currencyFormatter;
    if (!currencyFormatter) {
        currencyFormatter  = [[NSNumberFormatter alloc] init];
        [currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
        [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        [currencyFormatter setLocale:[NSLocale currentLocale]];
        if ([currencyFormatter generatesDecimalNumbers] || [[currencyFormatter roundingIncrement] floatValue] < 1) {
            [currencyFormatter setGeneratesDecimalNumbers:YES];
            [currencyFormatter setRoundingIncrement:[NSNumber numberWithFloat:0.01]];   
        }
    }

    return currencyFormatter;
}

(Внутренний if используется для того, чтобы средство форматирования всегда округляло до наименьшего десятичного разряда, например, даже для значений в швейцарских франках).

Что я получаю в консоли, это:

2012-03-29 00:35:38.490 myMutuo2[45396:fb03] String value = € 10.000,00
2012-03-29 00:35:38.494 myMutuo2[45396:fb03] Text field text = € 10.000,00
2012-03-29 00:35:38.497 myMutuo2[45396:fb03] Number value = 0

Странно то, что символ пробела между и 1 в первой строке отображается в консоли в виде точки в воздухе, а во второй строке эта точка исчезает. Я считаю, что это проблема, связанная с кодировкой.

Может ли кто-нибудь помочь мне решить эту проблему? Спасибо!

Изменить

Я изменил свой тестовый код на это:

NSNumberFormatter *nf = [Utils currencyFormatter];
NSNumber *n = [NSNumber numberWithInt:10000];
NSString *s = [nf stringFromNumber:n];
NSLog(@"String value = %@ (space code is %d)", s, [s characterAtIndex:1]);
UITextField *t = [[UITextField alloc] init];
t.text = s;
s = t.text;
NSLog(@"Text field text = %@ (space code is %d)", s, [s characterAtIndex:1]);
n = [nf numberFromString:s];
NSLog(@"Number value = %d", [n intValue]);

чтобы обнаружить это:

2012-03-29 02:29:43.402 myMutuo2[45993:fb03] String value = € 10.000,00 (space code is 160)
2012-03-29 02:29:43.405 myMutuo2[45993:fb03] Text field text = € 10.000,00 (space code is 32)
2012-03-29 02:29:43.409 myMutuo2[45993:fb03] Number value = 0

NSNumberFormatter записывает пробел как неразрывный пробел (ASCII-символ 160), а затем UITextField повторно кодирует этот пробел как простой пробел (ASCII-символ 32). Любое известное обходное решение для этого поведения? Возможно, я мог бы просто заменить пробел неразрывным пробелом, но... будет ли это работать для всех локалей?


person marzapower    schedule 28.03.2012    source источник
comment
это не работает только для вашей валюты. я проверил это и получил такое же нулевое значение, как вы сказали.   -  person Dinesh Raja    schedule 29.03.2012
comment
Смотрите мой отредактированный ответ во второй раз. Это может вам немного помочь.   -  person Dinesh Raja    schedule 29.03.2012


Ответы (2)


Возможный обходной путь: вы можете попытаться проанализировать только числовые значения (и знаки препинания) с помощью шаблона регулярного выражения и создать значение валюты на основе этого числа. Если вы сделаете это таким образом, возможно, даже более простительно для пользователя, если он наберет другой символ валюты или другие символы, которых там быть не должно...

person calimarkus    schedule 28.03.2012
comment
Я уже делаю это в предыдущей версии кода. Но я получаю странные ошибки, исключения и сбои, вероятно, с какой-то странной локалью. Я действительно хотел бы использовать магию NSNumberFormatter только для того, чтобы избавиться от всей этой пользовательской обработки строк и работать в контролируемой среде, в которой я кодирую и декодирую строки/числа, используя один и тот же объект форматирования. - person marzapower; 29.03.2012
comment
Между прочим... то, что пользователь помещает в UITextField, на самом деле генерируется через вызов метода stringFromNumber: NSNumberFormatter, поэтому я всегда знаю, что то, что содержит текстовое поле, было правильно отформатировано. Нет необходимости добавлять дополнительную логику для интерпретации этого значения. - person marzapower; 29.03.2012
comment
Чем вы могли бы просто сохранить введенное пользователем значение для последующего использования? зачем вам нужно, чем переконвертировать содержимое текстового поля? - person calimarkus; 29.03.2012
comment
Поскольку введенное пользователем значение записывается в UITextField с помощью метода textField:shouldChangeCharactersInRange:replacementString: в классе делегата. Этот метод автоматически преобразует введенные пользователем символы в строки в формате валюты. Строка сохраняется в свойстве text текстового поля для целей отображения, и я верну ее отсюда позже... - person marzapower; 29.03.2012

Я смог решить эту проблему, только расширив UITextField через собственный класс. В этот новый класс я помещаю новый @property типа NSString, в котором я храню "вычисленное" строковое значение для текстового поля. Эта строка никогда не будет изменена и сохранит исходную кодировку содержимого текстового поля.

Когда вам нужно снова работать с исходным нетронутым содержимым текстового поля, вы должны обратиться к этому новому свойству, а не к свойству text.

Использование отдельного строкового контейнера — единственный способ избежать этих странных изменений кодировки.

person marzapower    schedule 09.07.2012