如何在核心数据中添加每个对象的十进制值以得出总数?

时间:2014-07-06 22:13:07

标签: ios objective-c cocoa-touch core-data nsdecimalnumber

我要做的是遍历我的核心数据对象并添加每个项目的价格并返回该总计。我的以下代码一直在崩溃,我不知道为什么。以前我使用浮动但有人建议我使用NSDecimalNumber,因为它更准确。所以我开始转换我的代码来使用它。

代码循环浏览对象并添加价格然后返回总数:

+ (NSDecimalNumber *)totalPriceOfItems:(NSManagedObjectContext *)managedObjectContext
{
    NSError *error = nil;
    NSDecimalNumber *totalPrice = [[NSDecimalNumber alloc] init];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"BagItem"];

    // Get fetched objects and store in NSArray
    NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    for (BagItem *bagItem in fetchedObjects) {

     //   NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:[bagItem price]];
      //  NSString *price = [[[bagItem price] componentsSeparatedByCharactersInSet:
          //                  [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
            //               componentsJoinedByString:@""];
       totalPrice = [totalPrice decimalNumberByAdding:[bagItem price]];

        NSLog(@"total: %@", totalPrice);
    }

    return totalPrice;
}

错误:

** Terminating app due to uncaught exception 'NSDecimalNumberOverflowException', reason: 'NSDecimalNumber overflow exception'
*** First throw call stack:

2 个答案:

答案 0 :(得分:2)

我不确定为什么会出现溢出,因为NSDecimal的范围大于float的范围(它的范围不如{double的范围但是,1}}。

无论出于什么原因,滚动自己的循环并不是从Core Data请求汇总结果的正确方法:只要您的代码提供有关如何的正确说明,API就会让您要求数据库为您总计价格。汇总数据。您应该能够通过传递聚合表达式直接从Core Data获取总数,如下所示:

NSExpression *totalPriceExpr = [NSExpression expressionForFunction:@"sum:"
    arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:@"Price"]]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:@"totalPrice"];
[expressionDescription setExpression:totalPriceExpr];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"BagItem"];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

fetchedObjects将包含一个带有计数的项目。

答案 1 :(得分:2)

您获得的异常是因为您尝试添加两个非常大的数字以及表示它所需的位数对于NSDecimalNumber来说太大了。您的号码可能不是问题,它是您声明totalPrice变量的方式。

此行应更改

NSDecimalNumber *totalPrice = [[NSDecimalNumber alloc] init];

NSDecimalNumber *totalPrice = [NSDecimalNumber zero];

NSDecimalNumber是NSDecimal(本身围绕NSValue)的包装器,并没有为其init方法提供默认值。如果它做了什么应该值?一,零,100000?它实际上默认为NaN。从本质上讲,您的起始值可能占用了所有可用字节,每当您添加它时,您都会获得异常。

NSDecimalNumber具有内置的机制来处理溢出和其他数学错误(例如,除以零)。您可以通过使用setBehavior方法调用提供新的行为对象来更改默认行为。