今天我正在審查一些代碼,我被完全愚弄了。我看到這樣的事情在代碼比較使用const整數實例化的NSNumber對象的指針
...
NSNumber *myNumber = [NSNumber numberWithInteger:4];
...
if (myNumber == [NSNumber numberWithInteger:4)
{
...
}
...
當我讀到if
條件,我首先想到的是:WAW人!你怎麼能這樣做?您顯然在這裏比較指針,所以當然這個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其實這是一個級別的優化。不是在編譯時,而是在運行時完成的。 –