web-dev-qa-db-ja.com

NSStringの比較について

次の比較は両方ともtrueと評価されます。

1)

@"foo" == @"foo";

2)

NSString *myString1 = @"foo";
NSString *myString2 = @"foo";
myString1 == myString2;

ただし、等価演算子を使用して2つのNSStringsを比較できない場合があり、代わりに[myString1 isEqualToString:myString2]が必要な場合があります。誰かがこれに光を当てることができますか?

82
Yarin

==が機能する理由は、ポインターの比較のためです。 @""を使用して定数NSStringを定義すると、コンパイラーは参照を一意化します。コード内の他の場所で同じ定数が定義されている場合、それらはすべてメモリ内の同じ実際の場所を指します。

NSStringインスタンスを比較するときは、isEqualToString:メソッドを使用する必要があります。

NSString *myString1 = @"foo";
NSString *myString2 = @"foo";
NSString *myString3 = [[NSString alloc] initWithString:@"foo"];
NSLog(@"%d", (myString2 == myString3))  //0
NSLog(@"%d", (myString1 == myString2)); //1
NSLog(@"%d", [myString1 isEqualToString:myString2]); //1
NSLog(@"%d", [myString1 isEqualToString:myString3]); //1
[myString3 release];

編集:

NSString *myString3 = [[NSString alloc] initWithString:@"foo"]; 
// this is same with @"foo"

initWithString:は新しい参照を作成しなくなりました。initWithFormatが必要になります。

NSString *myString3 = [[NSString alloc] initWithFormat:@"foo"];
162
Jacob Relkin

等価演算子==は、ポインターアドレスのみを比較します。リテラル@""構文を使用して2つの同一の文字列を作成すると、コンパイラはそれらが等しいことを検出し、データを1回だけ保存します。したがって、2つのポインターは同じ場所を指します。ただし、他の手段で作成された文字列には、同じデータが含まれていても、異なるメモリ位置に保存されている場合があります。したがって、文字列を比較するときにalwaysisEqual:を使用する必要があります。

isEqual:isEqualToString:は常に同じ値を返しますが、isEqualToString:は高速です。

13
David M.

==はメモリ内の場所を比較します。 ptr == ptr2両方が同じメモリ位置を指している場合。これは、コンパイラがたまたま同一の文字列定数に対してone実際の文字列を使用するため、文字列定数で動作します。 It wont同じ内容の変数がある場合は機能します。変数が異なるメモリ位置を指しているためです。そのような場合はisEqualToStringを使用します。

10
mipadi

Cocoaでは、NSStringのisEqualToString:メソッドを使用して文字列が比較されます。

コンパイラーは2つの文字列リテラルをマージして1つのオブジェクトを指すのに十分なほど穏やかなので、ポインター比較は機能します。 2つの同一の文字列が1つのNSStringインスタンスを共有する保証はありません。

6
Nikolai Ruhe

文字列比較の代理としてのアドレス比較がどのように壊れるかを示す例:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSString *s1 = @"foo";
    NSString *s2 = @"foo";
    NSString *s3 = [[[NSString alloc] initWithString:@"foo"] autorelease];
    NSMutableString *s4 = [NSMutableString stringWithString:@"foobar"];
    [s4 replaceOccurrencesOfString:@"bar"
                        withString:@""
                           options:NSLiteralSearch
                             range:NSMakeRange(0, [s4 length])];

    NSLog(@"s1 = %p\n", s1);
    NSLog(@"s2 = %p\n", s2);
    NSLog(@"s3 = %p\n", s3);
    NSLog(@"s4 = %p\n", s4); // distinct from s1

    NSLog(@"%i", [s1 isEqualToString:s4]); // 1

    [pool release];
3
SK9

この例を確認してください。

NSString *myString1 = @"foo";
NSMutableString *myString2 = [[NSMutableString stringWithString:@"fo"] stringByAppendingString: @"o"];

NSLog(@"isEquality: %@", ([myString1 isEqual:myString2]?@"+":@"-")); //YES
NSLog(@"isEqualToStringity: %@", ([myString1 isEqualToString:myString2]?@"+":@"-")); //YES
NSLog(@"==ity: %@", ((myString1 == myString2)?@"+":@"-")); // NO

したがって、コンパイラは、isEqualToStringメソッドを使用して、NSStringのisEqualsおよび逆参照ポインターを処理する可能性がありますが、そうする必要はありませんでした。そして、あなたが見るように、ポインターは異なります。

0
Dmitry Zvorikin