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オブジェクトを割り当てることです。

しかし、今の私の質問は、なぜ彼らはそれをするのかということです。インスタンスを生成する時間よりも、メモリの浪費の方が重要ではありませんか?

それから私は考えました:フロートはどうですか?浮動小数点数は、2進表現などの理由で、equal演算子と実際に比較することはできません。そして、これが最後のテストです。

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での演算子の使用は、実装が0からXまでの整数(12または15など)に対して内部的にいくつかのグローバルインスタンスを使用する==ため、一部の場合にのみ機能します。NSNumber

ダースのNSNumberオブジェクトをメモリに保持するためのメモリは簡単です。

とにかく、==同じようにチェックするために演算子を使用しないでください。常にisEqual:(またはそのバリアント)を使用してください。このような実装の詳細やコンパイラの最適化に依存しないでください。

于 2012-12-21T19:11:27.653 に答える