2010-11-24 1 views
7

Учитывая следующий код:Почему NSNumber указывает на тот же адрес, когда значение равно?

int firstInt, secondInt; 

firstInt = 5; 
secondInt = 5; 

NSNumber *firstNumber = [NSNumber numberWithInt:firstInt]; 
NSNumber *secondNumber = [NSNumber numberWithInt:secondInt]; 

Почему на Земле сделать эти два экземпляра NSNumber указывают на тот же адрес?

Это сводит меня с ума!

Конечно, если вы меняете secondInt, скажите «4», все работает так, как ожидалось.

Спасибо, Жереми

+3

Почему вы заботитесь, если они тот же объект против двух различных объектов с такое же значение? – 2010-11-24 18:15:40

+0

Потому что, хотя они имеют одинаковое значение, мне нужно, чтобы они были отдельными экземплярами для вычисления оценки. – jchatard 2010-11-24 18:33:29

ответ

12

Это, вероятно, либо оптимизации компилятора или деталь реализации: а NSNumber неизменен нет никакой необходимости для них быть отдельные случаи.

EDIT: возможно, оптимизация реализации, думающая об этом. Вероятно, numberWithInt возвращает одноэлементный вызов при вызове с таким же целым числом.

+2

IIRC NSNumber имеет внутреннюю оптимизацию, которая возвращает одиночные числа для нижних целых чисел. На практике это не имеет значения, поскольку важно значение, а не адрес памяти. – Abizern 2010-11-24 18:19:33

+7

+1 «NSNumbers» для 0-12 являются одноточечными. – 2010-11-24 18:41:43

3

Потому что они имеют то же значение hash, поэтому NSNumber возвращает вам кеш-указатель из первого выделения.

6

Мой инстинкт дизайна подсказывает мне, что если личность счета важна в отличие от ее простой стоимости, вы должны сортировать какой-то объект оценки вместо обычных NSNumbers.

Но что в стороне: в крайнем случае вы можете использовать простой NSValue аналогично тому, как вы используете NSNumber. Это немного большая работа, чтобы получить значения, но у NSValue не существует коллаборационного поведения экземпляра NSNumber для небольших значений.

Некоторого код, который осуществляет все три модели поведения:

// NSValues are always distinct: 
    int foo = 5, bar = 5, outfoo, outbar; 
    NSValue *one = [NSValue value:&foo withObjCType:@encode(int)]; 
    NSValue *two = [NSValue value:&bar withObjCType:@encode(int)]; 

    [one getValue:&outfoo]; 
    [two getValue:&outbar]; 
    NSLog(@"one: %@ %x = %d ; two: %@ %x = %d", 
     [one class], one, outfoo, 
     [two class], two, outbar); 

    // by comparison with NSNumber behavior: 
    NSNumber *three = [NSNumber numberWithInt:6]; 
    NSNumber *four = [NSNumber numberWithInt:6]; 

    NSLog(@"three: %@ %x = %d ; four: %@ %x = %d", 
     [three class], three, [three intValue], 
     [four class], four, [four intValue]); 

    // except when the numbers are big: 
    NSNumber *five = [NSNumber numberWithInt:8675309]; 
    NSNumber *six = [NSNumber numberWithInt:8675309]; 

    NSLog(@"five: %@ %x = %d ; six: %@ %x = %d", 
     [five class], five, [five intValue], 
     [six class], six, [six intValue]); 

На моем макинтоше это дает выход как:

one: NSConcreteValue 42a8d0 = 5 ; two: NSConcreteValue 42a920 = 5 
three: NSCFNumber 404380 = 6 ; four: NSCFNumber 404380 = 6 
five: NSCFNumber 1324d0 = 8675309 ; six: NSCFNumber 106e00 = 8675309