I know to check whether 2 NSNumbers are the same you need to use ([A isEqualToNumber:B])
instead of (A == B)
unlike NSIntegers.
However, I have just realized (A == B)
works just fine in simulator and I'd like to know why.
The stranger thing is that on device, (A == B)
STILL WORKS as long as the numbers are below 13 and from 13 it will stop working then only ([A isEqualToNumber:B])
works but that is if they're bigger than 12 otherwise (A == B)
can still be used.
Why's that??
On NSNumber
there are optimizations in work, because they are used very often.
A. Twintones
The numbers from 0 to 12 are twintones (multitones). 12 is chosen, because hours and month indexes have this range. That means, that they are reused in every creation. In pseudo code (that would not work for many reasons):
id twintones[13];
+ (instancetype)newWithInteger:(int)value
{
if(value>=0 and value1=12)
{
if(!twintones[value])
{
twintone[value] = …; // Usual creation
}
return twintone[value];
}
// Usual creation
}
B. Tagged Pointers
Numbers are sometimes stored as tagged pointers. The basic idea is that a pointer in a 64-bit environment on OS X is always aligned at 16 byte boundaries, making the least 4 bits always 0.
abc…xyz0000
The last bit is used to mark a tagged pointer. This three unused bits left of it can be used to mark a class instead of having a full isa (class) pointer. If you store, i. e. a 3 in it (binary 011) – or whatever – after a check you can say: "That's an instance of NSNumber
storing an integer". The rest of the long word can be used to store the integer value. In such a case the pointer is the object, just encoded tricky. Two equal objects have the same "pointer", but it is no real pointer.
But the most important thing: You should never take any advantage out of this optimizations. They are solely optimizations.