Подтвердить что ты не робот

IOS - Почему это работает, когда я сравниваю два NSNumbers с "=="?

В моем приложении я случайно использовал "==" при сравнении двух объектов NSNumber:

NSNumber *number1;
NSNumber *number2;

Позже, после того, как были установлены значения этих объектов int, я случайно сделал это:

if (number1 == number2) {
    NSLog(@"THEY'RE EQUAL");
}

И, смутно, это сработало! Я мог бы поклясться, что меня научили делать так:

if (number1.intValue == number2.intValue) {
    NSLog(@"THEY'RE EQUAL");
}

Как использовалось использование "==" между двумя объектами NSNumber и почему? Означает ли это, что это хорошо, чтобы сравнить их таким образом, или это была просто случайность, и это, как правило, не гарантировано работать каждый раз? Это действительно смутило меня: (

4b9b3361

Ответ 1

Это, возможно, случайность.

От NSHipster:

Два объекта могут быть равными или эквивалентными друг другу, если они имеют общий набор наблюдаемых свойств. Тем не менее, эти два объекта могут по-прежнему считаться различными, каждый со своей собственной идентичностью. При программировании идентификатор объектов привязан к его адресу памяти.

Возможно, ваш оператор оценил значение YES, потому что number1 и number2 указывали на один и тот же объект. Это не сработает, если бы они имели одинаковое значение, но были двумя разными объектами.

Очевидная причина, по которой переменные NSNumber указывали бы на то же самое, будет заключаться в том, что вы явно назначили одно другому:

number1 = number2;

Но есть еще одна вещь. Из этого ответа:

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

Но в любом случае его безопаснее использовать isEqualToNumber:, поскольку не известно, какие другие " вещи" скрываются в глубинах кода, которые могут или не могут заставить его оценивать YES

От RyPress:

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

Ответ 2

Это не случайность. Это связано с функцией отмеченных указателей во время выполнения Objective-C при использовании процессора ARM64.

В Mac OS X 10.7 Apple представила тегированные указатели. Tagged pointers позволяют хранить определенные классы с небольшим количеством данных для каждого экземпляра внутри указателя. Это может устранить необходимость в распределении памяти для многих применений классов, таких как NSNumber, и может значительно повысить производительность. [...] на ARM64, среда выполнения Objective-C включает в себя тегированные указатели со всеми теми же преимуществами, которые они принесли на Mac

Источник

Ответ 3

Здесь два понятия равенства:

  • Идентификатор объекта: сравнение двух указателей указывает на те же объекты
  • Значение равенства: содержимое двух объектов равно.

В этом случае вам нужно равенство значений. В коде вы указываете два указателя на объекты NSNumber:

NSNumber *number1;
NSNumber *number2;

Но ни в коем случае не показывайте присваивание им значения. Это означает, что содержимое указателей может быть любым, и совершенно случайно у вас есть два указателя, указывающие на ячейки памяти (не обязательно одни и те же), где (number1.intValue == number2.intValue) оказывается истинным.

Вы можете ожидать, что поведение изменится нестабильными способами - например, как только вы добавите больше кода.

Ответ 4

Конечно, вы можете сравнить два NSNumber * с ==. Это скажет вам, равны ли указатели. Конечно, если указатели равны, то значения должны быть одинаковыми. Значения могут быть одинаковыми, если указатели не равны.

Теперь вам нужно знать, что MaxOS X и iOS выполняют некоторые значительные оптимизации для сохранения хранилища, особенно в 64-битном коде. Многие NSNumbers, представляющие одно и то же целочисленное значение, фактически будут тем же самым указателем.

NSNumber* value1 = [[NSNumber alloc] initWithInteger:1];
NSNumber* value2 = [[NSNumber alloc] initWithInteger:1];

Это будут те же указатели. В 64 бит, многие другие будут теми же указателями. Есть только два объекта NSNumber с булевыми значениями. Существует только один пустой объект NSArray и только один объект [NSNull null].

Не позволяйте этому убаюкать вас в каких-либо неправильных предположениях. Если вы хотите, чтобы два NSNumbers имели одинаковое значение, используйте isEqualToNumber: вы можете сказать "if (number1 == number2 || [number1 isEqualToNumber: number2])"; что штраф (не проверял, правильно ли я получил имена).