【发布时间】:2012-12-21 19:02:35
【问题描述】:
今天我正在审查一些代码,我完全被愚弄了。我在代码中看到了这样的东西
...
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
对此你有什么想说的吗?你真的认为这是最好的行为(而且更符合逻辑)吗? 感谢您分享您的知识!
【问题讨论】:
-
这是编译器优化:因为它们都是不可变对象并且在同一范围内,所以它们可能被创建一次而不是两次,没有任何后果。
-
@RamyAlZuhouri 实际上这是一个类级别的优化。不是在编译时完成,而是在运行时完成。
标签: objective-c ios foundation