Следующий метод принимает входные данные из UITextField и форматирует их для отображения. Этот код работал безупречно в течение многих лет, но только что сообщалось о проблеме на iPhone 6 Plus с iOS 8.1. Это происходит каждый раз для пользователя, но я не смог воспроизвести его. Я считаю, что это связано с преобразованиями и форматированием NSNumber/NSDecimalNumber в iOS 8, возможно, для 64-битного приложения/устройства.
Клавиатура, используемая для ввода, представляет собой цифровую клавиатуру, поэтому единственный текст, который можно ввести в текстовое поле, — это цифры 0–9 и «удалить».
По словам пользователя, происходит следующее:
Я пытаюсь ввести сумму бюджета в размере 250 долларов США. Когда я поднимаю его, сначала отображается 0,00. Затем, как только я ввожу 2, он показывает 220,02, затем, когда я ввожу 5, он говорит 2 200,25, затем, когда я ввожу 0, он показывает 22 002,50, если я пытаюсь стереть любые числа, я получаю действительно большое число.
Приведенный ниже код отлично работает с iOS 8.1, насколько я проверял, на всех устройствах в симуляторе, включая iPhone 6 Plus. Он также работает на устройстве iPhone 5S (64-разрядная версия) с iOS 8.1. У меня нет устройства iPhone 6 Plus.
Я пропустил что-то, что, как кто-то видит, может быть причиной этой ошибки?
РЕДАКТИРОВАТЬ: возможно ли это из-за того, что параметр decimalNumberWithMantissa должен быть беззнаковым длинным, и я использую NSInteger? Может ли это вызвать проблему, и если да, то почему это работало до iOS 8.1 на iPhone 6 Plus? Я бы сам проверил это, если бы мог...
EntryField UITextField инициализируется следующим образом:
entryField.text = [NSString stringWithFormat:@"%@", [[[ObjectsHelper sharedManager] currencyFullFormatter] stringFromNumber:[NSDecimalNumber zero]]];
и вот остальная часть соответствующего кода:
#define MAX__NUMBER_LENGTH 10
- (BOOL)textField:(UITextField *)textFieldHere shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
__ENTERING_METHOD__
NSMutableString *mstring = [[NSMutableString alloc] initWithString:[entryField text]];
if([string length] > 0){
//add case
[mstring insertString:string atIndex:range.location];
}
else {
//delete case - the length of replacement string is zero for a delete
[mstring deleteCharactersInRange:range];
}
NSString *clean_string = [[mstring componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:@""];
//clean up mstring since it's no longer needed
if ((clean_string.length >= MAX__NUMBER_LENGTH && range.length == 0) || ([clean_string length] == 0 && [string isEqualToString:@"0"]))
{
return NO; // return NO to not change text
}
else {
//get the cleaned price in the form of a NSNumber - it has not yet been scaled
NSNumber *priceNumberBeforeScale = [[DateHelper decimalFormatter] numberFromString:clean_string];
self.budgetIntNumber = priceNumberBeforeScale;
//get the cleaned price in the form of an integer - it has not yet been scaled
NSInteger priceIntBeforeScale = [priceNumberBeforeScale integerValue];
//scale the price for currency
NSDecimalNumber *priceScaled = [NSDecimalNumber decimalNumberWithMantissa:priceIntBeforeScale exponent:(0-[[[ObjectsHelper sharedManager] currencyScale] integerValue]) isNegative:NO];
//now format the price for currency
//and get the grouping separators added in and put it in the UITextField
entryField.text = [[[ObjectsHelper sharedManager] currencyFullFormatter] stringFromNumber:priceScaled];
//always return no since we are manually changing the text field
return NO;
}
}
Из DateHelper.m:
+ (NSNumberFormatter *)decimalFormatter {
__ENTERING_METHOD__
NSNumberFormatter *decimalFormatter = [[NSNumberFormatter alloc] init];
[decimalFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[decimalFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
return decimalFormatter;
}
Из ObjectsHelper.m:
- (NSNumberFormatter*)currencyFullFormatter {
__ENTERING_METHOD__
if (currencyFullFormatter != nil) {
return currencyFullFormatter;
}
currencyFullFormatter = [[NSNumberFormatter alloc] init];
[currencyFullFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyFullFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
return currencyFullFormatter;
}
- (NSNumber*)currencyScale {
__ENTERING_METHOD__
if (currencyScale != nil) {
return currencyScale;
}
self.currencyScale = [NSNumber numberWithInteger:[[[ObjectsHelper sharedManager] currencyFullFormatter] maximumFractionDigits]];
return currencyScale;
}
РЕДАКТИРОВАТЬ: Похоже, что этот ответ может быть на правильном пути, просто не совсем уверен, как это будет здесь переведено. Изменится ли
//get the cleaned price in the form of an integer - it has not yet been scaled
NSInteger priceIntBeforeScale = [priceNumberBeforeScale integerValue];
//scale the price for currency
NSDecimalNumber *priceScaled = [NSDecimalNumber decimalNumberWithMantissa:priceIntBeforeScale exponent:(0-[[[ObjectsHelper sharedManager] currencyScale] integerValue]) isNegative:NO];
to
//scale the price for currency
NSDecimalNumber *priceScaled = [NSDecimalNumber decimalNumberWithMantissa:[priceNumberBeforeScale unsignedLongLongValue] exponent:(0-[[[ObjectsHelper sharedManager] currencyScale] integerValue]) isNegative:NO];
возможно решить проблему?
[mstring replaceCharactersInRange:range withString:string]
. Обратите внимание, что пользователь может выбрать часть текстового поля и заменить ее с помощью копирования/вставки. - person Martin R   schedule 04.11.2014