NSStringの比較を理解する


83

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

1)

@"foo" == @"foo";

2)

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

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

回答:


165

==動作する理由は、ポインタの比較のためです。を使用して定数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"];

6
ほとんどのコンパイラは、最適化としてmyString3定数へのポインタも作成する"foo"ため、通常、これら3つの変数はすべて同じメモリ位置を指します。これは、gccとclangの両方に当てはまります(デフォルトのオプションを使用)。これをコンパイルしてみてください:gist.github.com/578568
mipadi

では、NSString変数を@ "..."とまったく同じように動作させるにはどうすればよいですか?私が尋ねる理由は、今のところ私のコードのb / cです。定数@ ".."は機能しますが、NSString変数に置き換えるとすぐにクラッシュします。ここを
2013年

2
+1、追加するだけです:isEqual:実際には完全な文字列比較を行いisEqualToStringNSObjectプロトコルリファレンスNSStringクラスリファレンスが(それぞれ)明示的に指定しているためと同じ結果を返します: "2つのオブジェクトが(によって-isEqual:)等しい場合、それらは同じでなければなりませんハッシュ値」および「2つ​​の文字列オブジェクトが等しい場合(isEqualToString:メソッドによって決定される場合)、それらは同じハッシュ値を持っている必要があります。」
エフェメラ2013

13

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

isEqual:とはisEqualToString:常に同じ値を返しますが、isEqualToString:より高速であることに注意してください。


2
またisEqualToString、渡されたパラメータがnil。の場合、:は例外を引き起こすことに注意してください。したがって、nil文字列と比較する可能性がある場合は、最初にnilチェックを実行するか、isEqual:
Sandy Chapman

10

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


「同じ内容の変数があると機能しない」という意味の例を教えていただけますか
Logicsaurus Rex

6

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

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


これについて公式に言及しているものはありますか?「2つの同一の文字列が1つのNSStringインスタンスを共有するという保証はありません。」
logicsaurus Rex

@ user3055655参照は必要ありません:NSString同じコンテンツを持つ2つの異なるインスタンスを作成するコードを簡単に記述できます:[NSMutableString string] != [NSMutableString string]
Nikolai Ruhe

@ user3055655私の主張が文字列リテラルに当てはまらないことを意味する場合:2つのバンドル(アプリとそのテストバンドルなど)のリテラルを試してください。
Nikolai Ruhe

同僚に見せたいものが欲しかった。可変文字列が等しいとは思いませんが、NSStringの2つのインスタンスを宣言し、@ "文字列値"を割り当てると、常に==機能が保証されます。ただし、1つのNSStringを削除し、値を割り当ててから、このように別のNSStringを削除NSString stringWithFormat:すると、実際には2つの異なる文字列が取得==されて失敗します。2つのNSString(NSMutableStringではない)インスタンスが1つのNSStringインスタンスを共有するという保証はないとおっしゃいましたが、共有できるように、その主張の証拠があるかどうかを尋ねました。
logicsaurus Rex

@ user3055655私が言ったように、異なるバンドルからのリテラルを試してください。
Nikolai Ruhe

3

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

    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];

0

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

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を処理する可能性がありますが、そうする必要はありませんでした。ご覧のとおり、ポインタは異なります。


-1
  NSString *str1=[NSString stringWithFormat:@"hello1"];
    NSString *str2=[NSString stringWithFormat:@"hello1"];
    NSString *str3 = [[NSString alloc] initWithString:@"hello1"];




// == compares the pointer but in our example we are taking same string value to different object  using @  so it will point to same address so output will be TRUE condition
    if (str1==str2) {
        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");
    }


    // == compares the pointer but in our example we are taking same string value to different object but we have allocated different string so both object will pount to different address so output will be FALSE condition
    if (str1==str3) {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }


  // compare:= compares the values of objects so output will be TRUE condition
    if ([str1 compare:str3]== NSOrderedSame) {
        NSLog(@"Both String are equal");

    }
    else{
        NSLog(@"Both String not are equal");

    }


    // isEqual compares the values of objects so output will be TRUE condition

    if ([str1 isEqual:str2]) {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }

    // isEqual compares the values of objects so output will be TRUE condition

    if ([str1 isEqual:str3]) {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }


    // isEqualToString compares the values of objects so output will be TRUE condition
    if ([str1 isEqualToString:str2]) {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }


    // isEqualToString compares the values of objects so output will be TRUE condition
    if ([str1 isEqualToString:str3]) {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }

    // == compares the pointers since we have initialized the same value to first object so the pointer be be same for same value so output will be TRUE condition
    if (str1==@"hello1") {

        NSLog(@"Both String are equal");
    }
    else{
        NSLog(@"Both String not are equal");

    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.