Как мне добавить десятичные значения каждого объекта в core data, чтобы получить итоговое значение?

#ios #objective-c #cocoa-touch #core-data #nsdecimalnumber

#iOS #objective-c #cocoa-touch #core-data #nsdecimalnumber

Вопрос:

Что я пытаюсь сделать, так это перебрать мои объекты core data, добавить цену каждого товара и вернуть это итоговое значение. Мой следующий код продолжает сбоить, и я не знаю почему. Ранее я использовал значения с плавающей запятой, но кто-то предложил мне использовать вместо этого 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:amp;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:
  

Ответ №1:

Исключение, которое вы получаете, связано с тем, что вы пытаетесь добавить два очень больших числа, а количество битов, необходимых для его представления, слишком велико для NSDecimalNumber . Скорее всего, проблема не в ваших числах, а в том, как вы объявляете переменную TotalPrice.

Эту строку следует изменить

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

Для

 NSDecimalNumber *totalPrice = [NSDecimalNumber zero];
  

NSDecimalNumber — это оболочка вокруг NSDecimal (сама по себе вокруг NSValue) и не предоставляет значение по умолчанию для своего метода инициализации. Если это произошло, каким должно быть значение? Единица, ноль, 100000? На самом деле по умолчанию используется значение NaN. По сути, ваше начальное значение, вероятно, занимает все доступные байты, и всякий раз, когда вы добавляете к нему, вы получаете исключение.

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

Комментарии:

1. NSDecimalNumber * TotalPrice = [[NSDecimalNumber alloc] initWithInt: 0]; Сработало для меня.

Ответ №2:

Я не уверен, почему вы получаете переполнение, потому что диапазон NSDecimal больше диапазона a float (хотя он не такой широкий, как диапазон a double ).

Независимо от причины, выполнение собственного цикла — неправильный подход к запросу агрегированных результатов из 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:amp;error];
  

fetchedObjects будет содержать один элемент со значением count.

Комментарии:

1. Очень полезно. Не представлял, что core data способен на это.