Comparing NSNumbers in Objective C
Asked Answered
N

5

69

I am a beginner at Objective-C and I am a bit confused at this scenario. I have the following code:

if (number1 < number2) {
    NSLog(@"THE FOLLOWING NUMBER ");
    NSLog(@"%@", number1);
    NSLog(@"IS LESS THAN");
    NSLog(@"%@", number2);
}

When I run this code I see really strange results like this:

2011-07-06 20:38:18.044 helloworld[1014:207] THE FOLLOWING NUMBER 
2011-07-06 20:38:18.047 helloworld[1014:207] 190.8776
2011-07-06 20:38:18.050 helloworld[1014:207] IS LESS THAN
2011-07-06 20:38:18.053 helloworld[1014:207] 96.75866

Both numbers are NSNumber objects, how could something like this happen? I am getting the two numbers by finding distances between sprites on the screen.

Any clues or advice would really be appreciated

Nasa answered 7/7, 2011 at 2:42 Comment(1)
Just as a note, you can combine those NSLogs by using NSLog(@"THE NUMBER %@ IS LESS THAN %@", number1, number2);Dispread
B
113

I assume number1 and number2 are pointers to objects. The < sign is comparing the pointers.

You need to compare the actual floatValue or doubleValue

if ([number1 doubleValue] < [number2 doubleValue]) 

....

Blackshear answered 7/7, 2011 at 2:46 Comment(5)
Alternatively, you can do if ([number1 compare:number2] == NSOrderedAscending).Baedeker
To tell you the truth, I downvoted because: a) Comparing floats is inherently inconsistent, and truthfully invalid (if anything, compare number1's float value minus number2's float value to some small epsilon), b) floats are evil, and untrustworthy; doubles are the way to go, if anything, and c) don't bother comparing numbers this way if they are integers. @Adam Rosenfield's comment is the best way to do it; trust NSNumber's comparison method to take care of it for you.Godsey
Oh, and also, the < isn't comparing pointers in this case; it's comparing numbers (the actual values that NSNumber provides). Don't want to be misleading!Godsey
@Itai Whilst I agree with using -compare:, the OP code was in fact comparing pointers (memory addresses converted to integers). It wasn’t comparing the actual values boxed in NSNumber instances.Countrywoman
@Bavarious Eh, whoops? You're right, my mistake. Misread that part. But the rest of my comment still stands, I think.Godsey
E
43

For cases where you simply want to test whether two NSNumber properties hold the same value, then from the Apple documentation it seems that using

- (BOOL)isEqualToNumber:(NSNumber *)aNumber

is the most straightforward and efficient way to compare two NSNumber values.

For example:

if ([someNumber isEqualToNumber:someOtherNumber])
{
    // The numbers hold the same value
}
else
{
    // The numbers hold different values
}

The documentation also says "This method is more efficient than compare: if you know the two objects are numbers."

Whenever you need to know whether a value is smaller or greater, they offer the

- (NSComparisonResult)compare:(NSNumber *)aNumber

method, but personally I would prefer at that point to just pull out the integer values (or double values) and use regular < and > operators to do the comparison, because that makes the code much easier to read, like so:

if (firstNumber.intValue > secondNumber.intValue)
{
    // First number is greater than the second number
}
else if (firstNumber.intValue == secondNumber.intValue)
{
    // The two numbers have the same value
}
else
{
    // The first number is smaller than the second number
}

Something like that is much easier to read than calls to -compare:, in my opinion.

Erik

Ellyellyn answered 23/1, 2014 at 2:12 Comment(1)
You say you would "pull out the integer values or the double values". Which ones? The compare: method will correctly compare both 64 bit integers and large double values that don't fit into an integer. In the first case, extracting double values would fail. In the second case, extracting integers would fail. Using compare: works.Plutonic
A
18

NSNumber has a method for comparison: - (NSComparisonResult)compare:(NSNumber*)aNumber

if([numberOne compare:numberTwo] == NSOrderedSame) 
{
      // proceed
}
Anthozoan answered 7/11, 2013 at 11:40 Comment(1)
This is the most accurate and reliable way to do this, since you don't risk losing precision.Dispread
H
1

These work great:

if ([number1 isLessThan:number2])
if ([number1 isLessThanOrEqualTo:number2])
if ([number1 isGreaterThan:number2])
if ([number1 isGreaterThanOrEqualTo:number2])
if ([number1 isEqualTo:number2])
if ([number1 isNotEqualTo:number2])
Handhold answered 17/11, 2021 at 5:1 Comment(0)
G
0

Swift 3.1

let number1 = NSNumber(value: 10.2)
let number2 = NSNumber(value: 20.2)
let result = number1.compare(number2)
if  result == .orderedAscending {

} else if result == .orderedDescending {

} else { // .orderedSame

}
Gentianella answered 11/5, 2017 at 8:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.