iOS - 为什么当我用“==”比较两个NSNumbers时它有效?

iOS - Why Does It Work When I Compare Two NSNumbers With "=="?

在我的应用中,我在比较两个 NSNumber 对象时不小心使用了“==”,如下所示:

NSNumber *number1;
NSNumber *number2;

后来,在设置这些对象的 int 值后,我不小心这样做了:

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

令人困惑的是,它奏效了!我可以发誓我被教导这样做:

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

在两个 NSNumber 对象之间使用“==”是如何工作的,为什么?这是否意味着可以这样比较它们,或者这只是侥幸,而且通常不能保证每次都有效?这真的让我很困惑:(

这可能是侥幸。

来自 NSHipster :

Two objects may be equal or equivalent to one another, if they share a common set of observable properties. Yet, those two objects may still be thought to be distinct, each with their own identity. In programming, an object’s identity is tied to its memory address.

您的语句可能计算为 YES,因为 number1number2 指向同一个对象。如果它们具有相同的值但是是两个不同的对象,这将不起作用。

NSNumber 变量指向同一个变量的明显原因是您明确地将一个变量分配给另一个变量,如下所示:

number1 = number2;

但是还有另外一件事。来自 this answer

This is likely either a compiler optimisation or an implementation detail: as NSNumber is immutable there's no need for them be separate instances. probably an implementation optimisation thinking about it. Likely numberWithInt returns a singleton when called subsequently with the same integer.

但是无论如何,使用 isEqualToNumber: 是最安全的,因为不知道还有什么其他“东西”潜伏在可能或不可能的代码深处使其计算 YES

来自 RyPress :

While it’s possible to directly compare NSNumber pointers, the isEqualToNumber: method is a much more robust way to check for equality. It guarantees that two values will compare equal, even if they are stored in different objects.

这里有两个平等的概念:

  • 对象标识:比较两个指针指向相同的对象
  • 值相等:两个对象的内容相等。

在这种情况下,您需要值相等。在您的代码中,您声明了两个指向 NSNumber 对象的指针:

NSNumber *number1;
NSNumber *number2;

但在任何时候都不会显示为它们赋值。这意味着指针的内容可以是任何东西,并且很可能你有两个指针指向 (number1.intValue == number2.intValue) 恰好为真的内存位置(不一定是相同的)。

您可以预期行为会以不稳定的方式发生变化 - 例如,一旦您添加更多代码。

当然可以用==比较两个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])";没关系(没有检查我的名字是否正确)。

这不是侥幸。 这是由于在使用 ARM64 CPU.

时 Objective-C 运行时的标记指针功能

In Mac OS X 10.7, Apple introduced tagged pointers. Tagged pointers allow certain classes with small amounts of per-instance data to be stored entirely within the pointer. This can eliminate the need for memory allocations for many uses of classes like NSNumber, and can make for a good performance boost.[…] on ARM64, the Objective-C runtime includes tagged pointers, with all of the same benefits they've brought to the Mac

Source