知识总结iOS项目

iOS 两个数相乘导致 NSDecimalNumber over

2017-10-10  本文已影响123人  zhangyin

先上一段代码,这段代码会导致overflow错误,使APP发生crash:

NSString *priceStr = @"";
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:priceStr];
NSDecimalNumber *countNum = [NSDecimalNumber decimalNumberWithString:stringWithNSInteger(NSIntegerMax)];
number = [number decimalNumberByMultiplyingBy:countNum];

在这段代码中,number的值为:NaN,即:not a number ,非数值;
而countNum 是一个最大的整数,
最后,将NaN和最大的整数相乘,导致了overflow的crash。

解决方案代码如下:

//定义数值处理的行为
    NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler
                                      decimalNumberHandlerWithRoundingMode:NSRoundBankers
                                      scale:2
                                      raiseOnExactness:NO
                                      raiseOnOverflow:NO
                                      raiseOnUnderflow:NO
                                      raiseOnDivideByZero:NO];
    
    NSString *priceStr = @"";
    NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:priceStr];
    NSDecimalNumber *countNum = [NSDecimalNumber decimalNumberWithString:stringWithNSInteger(NSIntegerMax)];

//使用数据处理行为的约定来进行运算,防止crash
    number = [number decimalNumberByMultiplyingBy:countNum withBehavior:roundUp];

上面这个例子不会crash了,但是最终number的值为NaN,需要后续的业务逻辑进行判断处理;

NSDecimalNumberHandler 用到的参数,其中:

NSRoundBankers

枚举,截断的方式;完整的定义如下:

// Rounding policies :
// Original
//    value 1.2  1.21  1.25  1.35  1.27
// Plain    1.2  1.2   1.3   1.4   1.3
// Down     1.2  1.2   1.2   1.3   1.2
// Up       1.2  1.3   1.3   1.4   1.3
// Bankers  1.2  1.2   1.2   1.4   1.3

typedef NS_ENUM(NSUInteger, NSRoundingMode) {
    NSRoundPlain,   // Round up on a tie
    NSRoundDown,    // Always down == truncate
    NSRoundUp,      // Always up
    NSRoundBankers  // on a tie round so last digit is even
};

scale

小数点后面的位数(精度)

raiseOnExactness

The exception raised if there is an exactness error.

raiseOnOverflow

是否抛出溢出错误,如果为YES,则APP会捕获溢出错误,这会导致APPcrash;

The exception raised on overflow.

raiseOnUnderflow

The exception raised on underflow.

raiseOnDivideByZero

The exception raised on divide by zero.


补充知识:

    if([number isEqualToNumber:NSDecimalNumber.notANumber]){
        NSLog(@"number is nan");
    }else{
        NSLog(@"number:%@",number);
    }
上一篇下一篇

猜你喜欢

热点阅读