A simple way to add all NSNumber
s in an array is (similar to what @Mahonor said in a comment):
NSArray *myArray = ... // array of NSNumber (or NSDecimalNumber) objects
NSNumber *sum = [myArray valueForKeyPath:@"@sum.self"];
Contrary to what the Collection Operators: sum states, the numbers in the array are not converted to double
, but to NSDecimal
. Therefore, no precision is lost when adding decimal numbers. Even NSNumber
objects which are not decimal numbers are converted to NSDecimal
for the addition. The result of the summation is an instance of NSDecimalValue
.
I verified (or tried to) that in two different ways. First, I ran this code
NSNumber *a = [NSNumber numberWithDouble:1.2];
NSNumber *b = [NSDecimalNumber decimalNumberWithString:@"-5.7"];
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];
and activated Objective-C message logging by setting the environment variable "NSObjCMessageLoggingEnabled=YES". As can be seen in the created "/tmp/msgSends-NNNN" file, decimalNumber
(and not doubleValue
) is sent to both number objects.
Second, I created a custom class implementing both decimalValue
and doubleValue
, and applied @sum.self
to an array of objects of the custom class:
@interface MyClass : NSObject
@property (nonatomic, assign) double value;
@end
@implementation MyClass
- (NSDecimal)decimalValue
{
return [[NSNumber numberWithDouble:self.value] decimalValue];
}
- (double)doubleValue
{
return self.value;
}
@end
MyClass *a = [MyClass new]; a.value = 1.2;
MyClass *b = [MyClass new]; b.value = -5.7;
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];
By setting breakpoints in both methods, it is seen that only decimalValue
is used for the summation (and valueForKeyPath:@"@sum.self"
throws an exception if the class does not implement decimalValue
).
One can also see that decimalValue
is called from
-[NSArray(NSKeyValueCoding) _sumForKeyPath:]
and the assembler code for this method shows that NSDecimalAdd
is uses to add the numbers.
[myArray valueForKeyPath:@"@sum.self"]
. – Mastery