今天我正在审查一些代码而且我完全被愚弄了。我在代码中看到了类似的东西
...
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
你能说些什么?你真的认为这是最好的行为(而且逻辑越多)? 感谢您分享您的知识!
答案 0 :(得分:3)
使用带有NSNumber的==
运算符仅适用于某些情况,因为NSNumber
实现在内部使用一些全局实例用于整数0到X(12或15或其他)。
在内存中保存十几个NSNumber
对象的内存非常简单。
无论如何,切勿使用==
运算符进行同等检查。始终使用isEqual:
(或其变体)。永远不要依赖这样的实现细节或编译器优化。