iOS 8号码转换/格式化错误?(不能重现)

SAH*_*AHM 5 64-bit nsnumber nsdecimalnumber ios8 iphone-6-plus

以下方法从UITextField获取输入并将其格式化以供显示.这段代码多年来一直运行良好,但是使用iOS 8.1在iPhone 6 Plus上报告了一个问题.它每次都发生在用户身上,但我无法重现它.我相信它与iOS 8上的NSNumber/NSDecimalNumber转换和格式有关,可能对于64位应用程序/设备.

用于输入的键盘是数字键盘,因此可输入文本字段的唯一文本是数字0-9和"删除".

根据用户的说法,这就是发生的事情:

我想输入250美元的预算金额.当我把它拉起来时,最初是显示0.00.然后,一旦我输入2,它然后显示220.02然后当我输入5它说2,200.25然后当我输入0时它会出现22,002.50如果我试图删除任何数字它出现了一个非常大的数字.

根据我的测试,下面的代码在iOS 8.1中与模拟器中的每个设备(包括iPhone 6 Plus)完美配合.它也适用于iOS 8.1的iPhone 5S设备(64位).我没有iPhone 6 Plus设备.

我错过了某人看到可能导致此错误的内容吗?

编辑:这可能是因为decimalNumberWithMantissa参数应该是unsigned long long我使用NSInteger?这会导致问题,如果是这样,为什么它会在iPhone 6 Plus上的iOS 8.1之前有效?如果可以的话,我会亲自检查一下......

entryField UITextField初始化如下:

entryField.text = [NSString stringWithFormat:@"%@", [[[ObjectsHelper sharedManager] currencyFullFormatter] stringFromNumber:[NSDecimalNumber zero]]];
Run Code Online (Sandbox Code Playgroud)

这是相关代码的其余部分:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

来自DateHelper.m:

+ (NSNumberFormatter *)decimalFormatter {   

        __ENTERING_METHOD__
        NSNumberFormatter *decimalFormatter = [[NSNumberFormatter alloc] init];
        [decimalFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
        [decimalFormatter setNumberStyle:NSNumberFormatterDecimalStyle];

        return decimalFormatter;
    }
Run Code Online (Sandbox Code Playgroud)

来自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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:似乎这个答案可能在正确的轨道上,只是不确定这将如何翻译在这里.会改变

    //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];
Run Code Online (Sandbox Code Playgroud)

    //scale the price for currency
    NSDecimalNumber *priceScaled = [NSDecimalNumber decimalNumberWithMantissa:[priceNumberBeforeScale unsignedLongLongValue] exponent:(0-[[[ObjectsHelper sharedManager] currencyScale] integerValue]) isNegative:NO];
Run Code Online (Sandbox Code Playgroud)

有可能解决问题吗?

SAH*_*AHM 1

iOS 8 的自定义键盘似乎可能存在问题。需要进一步调查,但目前至少有一次此问题已通过从设备中删除自定义键盘得到解决。

编辑:是否已确认此特定问题是由 iOS 8 自定义键盘应用程序引起的。该问题已报告给该应用程序的发行商。