【问题标题】:Understanding NSString comparison理解 NSString 比较
【发布时间】:2011-04-11 20:08:53
【问题描述】:

以下两个比较结果都为真:

1)

@"foo" == @"foo";

2)

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

但是,在某些情况下,两个NSStrings 肯定无法使用相等运算符进行比较,而是需要[myString1 isEqualToString:myString2]。有人可以对此有所了解吗?

【问题讨论】:

    标签: objective-c cocoa nsstring string-comparison


    【解决方案1】:

    == 起作用的原因是指针比较。当您使用@"" 定义常量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"];
    

    【讨论】:

    • 大多数编译器也会将myString3 设为指向常量"foo" 的指针作为优化,因此通常所有这三个变量都会指向同一个内存位置。对于 gcc 和 clang(使用默认选项)都是如此。尝试编译:gist.github.com/578568
    • 那么我怎样才能使 NSString 变量的行为与@"..." 完全一样?我问的原因是现在我的代码中的 b/c 常量 @".." 可以工作,但是一旦我用 NSString 变量替换它就会崩溃。请参阅here
    • +1,补充一句:isEqual: 实际上做了一个完整的字符串比较并返回与isEqualToString 相同的结果,因为 NSObject 协议参考NSString 类参考 明确指定(分别):“如果两个对象相等(-isEqual:),它们必须具有相同的哈希值”和“如果两个字符串对象相等(由 isEqualToString: 方法确定) ),它们必须具有相同的哈希值。”
    【解决方案2】:
      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");
    
        }
    

    【讨论】:

      【解决方案3】:

      看看这个例子:

      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,尽管它没有这样做。如您所见,指针是不同的。

      【讨论】:

        【解决方案4】:

        一个示例说明地址比较作为字符串比较的代理将如何中断:

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

        【讨论】:

          【解决方案5】:

          == 比较内存中的位置。 ptr == ptr2 如果它们都指向同一个内存位置。这恰好适用于字符串常量,因为编译器碰巧将 one 实际字符串用于相同的字符串常量。如果您有具有相同内容的变量,它不会起作用,因为它们将指向不同的内存位置;在这种情况下使用isEqualToString

          【讨论】:

          • 你能举个例子说明一下“如果你有相同内容的变量,它就行不通”
          【解决方案6】:

          相等运算符== 只比较指针地址。当您使用文字 @"" 语法创建两个相同的字符串时,编译器将检测它们是否相等,并且只存储一次数据。因此,这两个指针指向同一个位置。但是,通过其他方式创建的字符串可能包含相同的数据,但存储在不同的内存位置。因此,您应该始终在比较字符串时使用isEqual:

          注意isEqual:isEqualToString: 总是返回相同的值,但isEqualToString: 更快。

          【讨论】:

          • 还要注意isEqualToString:如果传递给它的参数是nil会引发异常。因此,如果您有机会与 nil 字符串进行比较,您应该先进行 nil 检查或使用 isEqual:
          【解决方案7】:

          在 Cocoa 中使用 NSString 的 isEqualToString: 方法比较字符串。

          指针比较适用于您的情况,因为编译器足够温和,可以合并两个字符串文字以指向一个对象。不能保证两个相同的字符串共享一个 NSString 实例。

          【讨论】:

          • 您对此有官方参考吗? “不能保证两个相同的字符串共享一个 NSString 实例。”
          • @user3055655 我不需要参考:您可以轻松编写代码来创建两个具有相同内容的不同NSString 实例:[NSMutableString string] != [NSMutableString string]
          • @user3055655 如果您的意思是我的说法不适用于字符串文字:尝试来自两个包的文字(如应用程序及其测试包)。
          • 我只是想向同事展示一些东西。我不希望可变字符串相等,但是声明两个 NSString 实例并分配一些 @"string value" 总是保证 == 功能。但是,如果您删除一个 NSString,分配一个值,然后像 NSString stringWithFormat: 这样删除另一个 NSString,那么您实际上会得到两个不同的字符串,== 将失败。你说不能保证两个 NSString(不是 NSMutableString)实例将共享一个 NSString 实例,我只是问你是否有任何证据证明这一说法,以便我可以分享。
          • @user3055655 正如我所说,尝试来自不同包的文字。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-25
          • 1970-01-01
          • 1970-01-01
          • 2013-10-12
          • 2012-10-07
          • 1970-01-01
          相关资源
          最近更新 更多