2012-12-21 18 views
3

今天我正在審查一些代碼,我被完全愚弄了。我看到這樣的事情在代碼比較使用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 

你對此有何評論?你真的認爲這是最好的行爲(和更多的邏輯)嗎? 感謝您分享您的知識!

+0

這是編譯器優化:因爲它們都是不可變對象並且在相同範圍內,所以它們可以被創建一次而不是兩次,而沒有後果。 –

+1

@RamyAlZuhouri其實這是一個級別的優化。不是在編譯時,而是在運行時完成的。 –

回答

3

的使用==運營商的NSNumber的只能在某些情況下,因爲NSNumber實現內部通過X(12或15或東西)使用爲整數0一些全局實例。

內存中容納一打NSNumber對象是微不足道的。

無論如何,千萬不要使用==運營商來平等地檢查。始終使用isEqual:(或其變體)。永遠不要依賴這樣的實現細節或編譯器優化。

+2

正確地從-1到12的數字被緩存,從[CFNumber源代碼]中的__CFNumberCache定義可以看出(http://www.opensource.apple.com/source/CF/CF-744.12/CFNumber 。C)。 –