Hiểu so sánh NSString


83

Cả hai so sánh sau đây đều đánh giá là true:

1)

@"foo" == @"foo";

2)

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

Tuy nhiên, chắc chắn NSStringcó những lúc không thể so sánh hai s bằng toán tử bình đẳng và [myString1 isEqualToString:myString2]thay vào đó , nó được yêu cầu. Ai đó có thể làm sáng tỏ về điều này?

Câu trả lời:


165

Lý do tại sao ==hoạt động là vì so sánh con trỏ. Khi bạn xác định một hằng số NSStringbằng cách sử dụng @"", trình biên dịch thống nhất tham chiếu. Khi các hằng số giống nhau được xác định ở những vị trí khác trong mã của bạn, tất cả chúng sẽ trỏ đến cùng một vị trí thực tế trong bộ nhớ.

Khi so sánh các NSStringtrường hợp, bạn nên sử dụng isEqualToString:phương pháp:

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

Biên tập:

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

initWithString:không tạo tham chiếu mới nữa, bạn sẽ cần initWithFormat,

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

6
Hầu hết các trình biên dịch cũng sẽ tạo myString3một con trỏ tới hằng số "foo"như một sự tối ưu hóa, vì vậy nói chung, cả ba biến này sẽ trỏ đến cùng một vị trí bộ nhớ. Điều này đúng cho cả gcc và clang (với các tùy chọn mặc định). Hãy thử biên dịch cái này: gist.github.com/578568
mipadi

và vì vậy, làm cách nào để biến NSString hoạt động chính xác như @ "..."? lý do tôi hỏi là b / c trong mã của tôi ngay bây giờ hằng @ ".." công trình nhưng nó bị treo ngay sau khi tôi thay thế nó bằng một biến NSString .. thấy ở đây
abbood

2
+1, Chỉ cần thêm: isEqual:trên thực tế thực hiện so sánh chuỗi đầy đủ và trả về cùng một kết quả isEqualToStringTham chiếu giao thức NSObjectTham chiếu lớp NSString chỉ định rõ ràng (tương ứng): "Nếu hai đối tượng bằng nhau (bằng -isEqual:) thì chúng phải có cùng giá trị băm "VÀ" Nếu hai đối tượng chuỗi bằng nhau (như được xác định bởi phương thức isEqualToString:), chúng phải có cùng giá trị băm. "
Ephemera

13

Toán tử bình đẳng ==chỉ so sánh các địa chỉ con trỏ. Khi bạn tạo hai chuỗi giống nhau bằng @""cú pháp chữ , trình biên dịch sẽ phát hiện chúng bằng nhau và chỉ lưu trữ dữ liệu một lần. Do đó, hai con trỏ trỏ đến cùng một vị trí. Tuy nhiên, các chuỗi được tạo bằng các phương tiện khác có thể chứa dữ liệu giống hệt nhau, nhưng được lưu trữ tại các vị trí bộ nhớ khác nhau. Do đó, bạn nên luôn sử dụng isEqual:khi so sánh các chuỗi.

Lưu ý rằng isEqual:isEqualToString:luôn trả về cùng một giá trị, nhưng isEqualToString:nhanh hơn.


2
Cũng lưu ý rằng isEqualToString: sẽ gây ra một ngoại lệ nếu tham số được truyền cho nó nil. Vì vậy, nếu có một cơ hội bạn đang so sánh với một chuỗi con số không, bạn có nên làm một tấm séc đầu tiên bằng không hoặc sử dụngisEqual:
Sandy Chapman

10

==so sánh các vị trí trong bộ nhớ. ptr == ptr2nếu cả hai đều trỏ đến cùng một vị trí bộ nhớ. Điều này xảy ra với các hằng số chuỗi vì trình biên dịch tình cờ sử dụng một chuỗi thực cho các hằng số chuỗi giống hệt nhau. Nó sẽ không hoạt động nếu bạn có các biến có cùng nội dung, vì chúng sẽ trỏ đến các vị trí bộ nhớ khác nhau; sử dụng isEqualToStringtrong trường hợp như vậy.


Bạn có thể soi sáng với một ví dụ về những gì bạn có nghĩa là "nó wont work nếu bạn có các biến với những nội dung tương tự"
Logicsaurus Rex

6

Trong Cacao, các chuỗi được so sánh bằng cách sử dụng isEqualToString:phương pháp của NSString .

So sánh con trỏ hoạt động trong trường hợp của bạn vì trình biên dịch đủ nhẹ nhàng để hợp nhất hai chuỗi ký tự để trỏ đến một đối tượng. Không có gì đảm bảo rằng hai chuỗi giống nhau chia sẻ một NSStringphiên bản.


Bạn có bất kỳ tài liệu tham khảo chính thức nào về điều này không? "Không có gì đảm bảo rằng hai chuỗi giống nhau chia sẻ một phiên bản NSString."
Logicsaurus Rex

@ user3055655 Tôi không cần một tài liệu tham khảo: Bạn có thể mã dễ dàng ghi mà tạo ra hai phân biệt NSStringtrường hợp với nội dung giống hệt nhau:[NSMutableString string] != [NSMutableString string]
Nikolai Ruhe

@ user3055655 Nếu ý của bạn là khẳng định của tôi không đúng đối với các ký tự chuỗi: Hãy thử các ký tự từ hai gói (như một ứng dụng và gói thử nghiệm của nó).
Nikolai Ruhe

Tôi chỉ muốn một cái gì đó để cho đồng nghiệp xem. Tôi sẽ không mong đợi các chuỗi có thể thay đổi bằng nhau, nhưng việc khai báo hai phiên bản của NSString và gán một số @ "giá trị chuỗi" luôn đảm bảo ==chức năng. Tuy nhiên, nếu bạn bỏ qua một NSString, gán một giá trị, và sau đó loại bỏ một NSString khác như thế này NSString stringWithFormat:thì trên thực tế, bạn sẽ nhận được hai chuỗi khác nhau ==sẽ bị lỗi. Bạn đã nói rằng không có gì đảm bảo rằng hai phiên bản NSString (không phải NSMutableString) sẽ chia sẻ một phiên bản NSString và tôi chỉ hỏi bạn có bất kỳ bằng chứng nào về tuyên bố đó không để tôi có thể chia sẻ nó.
Logicsaurus Rex

@ user3055655 Như tôi đã nói, hãy thử các ký tự từ các gói riêng biệt.
Nikolai Ruhe

3

Một ví dụ minh họa cách so sánh địa chỉ làm đại diện cho so sánh chuỗi sẽ phá vỡ:

    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

Kiểm tra ví dụ này:

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

Vì vậy, trình biên dịch có khả năng sử dụng phương thức isEqualToString để xử lý isEquals cho các con trỏ và con trỏ tham chiếu của NSString, mặc dù không phải như vậy. Và các con trỏ khác nhau, như bạn thấy.


-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");

    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.