3

今天我正在审查一些代码,我完全被愚弄了。我在代码中看到了类似的东西

...
NSNumber *myNumber = [NSNumber numberWithInteger:4];
...
if (myNumber == [NSNumber numberWithInteger:4)
{
...
}
...

当我读到那个if条件时,我的第一个想法是:哇,伙计!你怎么能那样做?您显然是在比较指针,所以if当您在正确的位置生成实例时,当然不会执行其中的代码,因此对象永远不会相同!

我的(大)惊喜是实际上if正在被处决!所以我生成了一些测试来加深正在发生的事情,我得到了这个:

NSInteger intValue = 5;
NSNumber *anIntNumber = [NSNumber numberWithInteger:intValue];
NSNumber *anotherIntNumber = [NSNumber numberWithInteger:intValue];
NSLog(@"%p vs %p -> %@", anIntNumber, anotherIntNumber, ((anIntNumber == anotherIntNumber) ? @"YES" : @"NO"));

这是结果:

0x7462560 vs 0x7462560 -> YES

所以我记得我在堆栈溢出的某个地方读到,当程序开始时,常量 NSString 存储在内存堆栈的某个地方。然后我运行这段代码来检查 NSString 实例是否发生了同样的事情:

NSString *aString = @"FOO";
NSString *anotherString = @"FOO";
NSLog(@"%p vs %p -> %@", aString, anotherString, ((aString == anotherString) ? @"YES" : @"NO"));

这是结果:

0x35cc vs 0x35cc -> YES

所以是的,尽管不是故意的,但实例是相同的。我可以用这些结果想象的是,系统也在内存堆栈中的某处分配了所有用常量整数实例化的 NSNumber 对象。

但我现在的问题是:他们为什么要这样做?内存的浪费不是比生成实例的时间更重要吗?

然后我想:花车呢?由于二进制表示和所有这些东西,浮点数不能真正与等号运算符进行比较。这是最后一个测试:

float floatValue = 5.41553f;
NSNumber *aFloatNumber = [NSNumber numberWithFloat:floatValue];
NSNumber *anotherFloatNumber = [NSNumber numberWithFloat:floatValue];
NSLog(@"%p vs %p -> %@", aFloatNumber, anotherFloatNumber, ((aFloatNumber == anotherFloatNumber) ? @"YES" : @"NO"));

这是唯一的预期结果!

0x712f180 vs 0x74299a0 -> NO

对此你能说什么?你真的认为这是最好的行为(而且更符合逻辑)吗?感谢您分享您的知识!

4

1 回答 1

3

==仅在某些情况下使用带有 NSNumber 的运算符,因为NSNumber实现在内部使用了一些全局实例来表示整数 0 到 X(12 或 15 或其他)。

在内存中保存十几个NSNumber对象的内存是微不足道的。

无论如何,永远不要使用==运算符进行平等检查。始终使用isEqual:(或其变体)。永远不要依赖这样的实现细节或编译器优化。

于 2012-12-21T19:11:27.653 回答