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

pkamb
  • 33,281
  • 23
  • 160
  • 191
Doug Molineux
  • 12,283
  • 25
  • 92
  • 144
  • 1
    Just as a note, you can combine those `NSLog`s by using `NSLog(@"THE NUMBER %@ IS LESS THAN %@", number1, number2);` – Ky - Sep 11 '15 at 21:31

5 Answers5

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]) 

....

Kal
  • 24,724
  • 7
  • 65
  • 65
  • 37
    Alternatively, you can do `if ([number1 compare:number2] == NSOrderedAscending)`. – Adam Rosenfield Jul 07 '11 at 03:06
  • 3
    To tell you the truth, I downvoted because: a) Comparing `float`s is inherently inconsistent, and truthfully invalid (if anything, compare `number1`'s `float` value minus `number2`'s `float` value to some small epsilon), b) `float`s are evil, and untrustworthy; `double`s 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. – Itai Ferber Jul 07 '11 at 03:54
  • 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! – Itai Ferber Jul 07 '11 at 04:00
  • @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. –  Jul 07 '11 at 05:48
  • @Bavarious Eh, whoops? You're right, my mistake. Misread that part. But the rest of my comment still stands, I think. – Itai Ferber Jul 07 '11 at 06:02
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

Erik van der Neut
  • 2,245
  • 2
  • 22
  • 21
  • 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. – gnasher729 Mar 31 '14 at 09:56
18

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

if([numberOne compare:numberTwo] == NSOrderedSame) 
{
      // proceed
}
JastinBall
  • 873
  • 8
  • 25
  • 3
    This is the most accurate and reliable way to do this, since you don't risk losing precision. – Ky - Sep 11 '15 at 20:45
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])
AgentRev
  • 749
  • 1
  • 8
  • 20
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

}
William Hu
  • 15,423
  • 11
  • 100
  • 121